Java进程与线程总结
[TOC]
图解
进程与线程
Thread类的使用
多线程的实现方式
方式1:继承Thread类
- 定义一个类MyThread继承Thread类
- 在MyThread类中重写run()方法
- 创建MyThread类的对象
- 启动线程
两个小问题:
- 为什么要重写run()方法?
- run0方法和start()方法的区别?
- run():封装线程执行的代码,直接调用,相当于普通方法的调用
- start():启动线程;然后由VM调用此线程的runO方法
代码
package 基础知识.进程和线程.A1_Thread类;
public class RunsName {
public static void main(String[] args) { System.out.println(Thread.currentThread().getName());
method1(); method2();
}
public static void method1(){ MyThreadName t1 = new MyThreadName(); MyThreadName t2 = new MyThreadName();
t1.start(); t2.start(); }
public static void method2(){ MyThreadName tn1 = new MyThreadName(); MyThreadName tn2 = new MyThreadName(); tn1.setName("Ayaka001"); tn2.setName("Ayaka002"); tn1.start(); tn2.start(); }
}
class MyThreadName extends Thread {
@Override public void run() { System.out.println(Thread.currentThread().getName()); for (int i = 0; i < 100; i++) { System.out.println(getName() + " : " + i); } } }
|
线程调度
线程调度
线程有两种调度模型
分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程
获取的CPU时间片相对多一些
Java使用的是抢占式调度模型
假如计算机只有一个CPU,那么CPU在某一个时刻只能执行一条指铃,线程只有得到CPU时间片,也就是使用权,才可以执行指令。所以说多线程程序的执行是有随机性,因为谁抢到CPU的使用权是不一定的
Thread类中设置和获取线程优洗级的方法
- public final int getPriority0:返回此线程的优先级
- public final void setPriority(int newPriority):更改此线程的优先级
线程默认优先级是5;线程优先级的范围是:1-10
线程优先级高仅仅表示线程获取的CU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到你想要的效果
代码
public class runs {
public static void main(String[] args) { ThreadPriority tp1 = new ThreadPriority(); ThreadPriority tp2 = new ThreadPriority(); ThreadPriority tp3 = new ThreadPriority();
tp1.setName("高铁"); tp2.setName("飞机"); tp3.setName("拖拉机");
System.out.println(Thread.MIN_PRIORITY); System.out.println(Thread.NORM_PRIORITY); System.out.println(Thread.MAX_PRIORITY); System.out.println("还可以在中间取int设置调度");
System.out.println("==========================");
priority_MIN_TO_MAX(tp1,5); priority_MIN_TO_MAX(tp2,10); priority_MIN_TO_MAX(tp3,1);
System.out.println(tp1.getPriority()); System.out.println(tp2.getPriority()); System.out.println(tp3.getPriority());
}
public static void priority_NORM(ThreadPriority tp){ tp.start(); }
public static void priority_MIN_TO_MAX(ThreadPriority tp,int p){ tp.setPriority(p); tp.start(); } }
public class ThreadPriority extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName() + ": " + i); } } }
|
线程控制
sleep线程停留
package 基础知识.进程和线程.A3_线程控制;
public class Runs_sleep {
public static void main(String[] args) {
ThreadSleep ts1 = new ThreadSleep(); ThreadSleep ts2 = new ThreadSleep(); ThreadSleep ts3 = new ThreadSleep(); ts1.setName("曹操"); ts2.setName("刘备"); ts3.setName("孙权");
ts1.start(); ts2.start(); ts3.start(); }
}
class ThreadSleep extends Thread { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName() + ":" + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
|
join等待线程死亡
package 基础知识.进程和线程.A3_线程控制;
public class Runs_join {
public static void main(String[] args) {
ThreadJoin tj1 = new ThreadJoin(); ThreadJoin tj2 = new ThreadJoin(); ThreadJoin tj3 = new ThreadJoin(); tj1.setName("曹操"); tj2.setName("曹丕"); tj3.setName("曹植");
tj1.start();
try { tj1.join(); } catch (InterruptedException e) { e.printStackTrace(); }
tj2.start(); tj3.start();
}
}
class ThreadJoin extends Thread{
@Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName() + ":" + i); } }
}
|
setDaemon 守护线程
package 基础知识.进程和线程.A3_线程控制;
public class Runs_setDaemon {
public static void main(String[] args) {
Thread_setDaemon td1 = new Thread_setDaemon(); Thread_setDaemon td2 = new Thread_setDaemon();
td1.setName("关羽"); td2.setName("张飞");
td1.setDaemon(true); td2.setDaemon(true);
td1.start(); td2.start();
try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); }
for (int i = 0; i < 10; i++) { System.out.println("大哥刘备:" + i); }
}
}
class Thread_setDaemon extends Thread {
@Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName() + ":" + i); } } }
|
线程生命周期
Runnable接口 实现多线程
package 基础知识.进程和线程.A5_Runnable接口;
public class Runs { public static void main(String[] args) { MyRunnable my = new MyRunnable();
Thread t1 = new Thread(my); Thread t2 = new Thread(my);
Thread t3 = new Thread(my, "Ayaka");
t1.start(); t2.start(); t3.start();
} }
class MyRunnable implements Runnable {
@Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); } } }
|
线程同步
售票案例与问题
public class MyRunnable implements Runnable { private int tick = 100; @Override public void run() { while (true) { if (tick > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第:" + tick + "张票"); tick--;
} } } }
package 基础知识.进程和线程.A6_线程同步.B1_售票案例;
public class Runs {
public static void main(String[] args) {
MyRunnable runn = new MyRunnable();
Thread t1 = new Thread(runn, "窗口1"); Thread t2 = new Thread(runn, "窗口2"); Thread t3 = new Thread(runn, "窗口3");
t1.start(); t2.start(); t3.start();
}
}
|
售票案例中的问题
解决方案 与 规范
package 基础知识.进程和线程.A6_线程同步.B2_售票改进_多线程安全_同步代码块;
public class MyRunnable implements Runnable {
private int tick = 100; private Object obj = new Object();
@Override public void run() { while (true) { synchronized (obj) { if (tick > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第:" + tick + "张票"); tick--; } } } } }
public class Runs {
public static void main(String[] args) { MyRunnable runn = new MyRunnable();
Thread t1 = new Thread(runn, "窗口1"); Thread t2 = new Thread(runn, "窗口2"); Thread t3 = new Thread(runn, "窗口3");
t1.start(); t2.start(); t3.start(); } }
|
同步方法
代码
public class MyRunnable implements Runnable { private int tick = 100; private Object object = new Object(); private int jia = 0;
@Override public void run() { while (true) { if (jia % 2 == 0) { synchronized (this) { if (tick > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第:" + tick + "张票"); tick--;
} } } else {
method(); } jia++; } }
public synchronized void method() {
if (tick > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第:" + tick + "张票"); tick--; } } }
public class RunsMethod {
public static void main(String[] args) { MyRunnable run = new MyRunnable();
Thread t11 = new Thread(run, "窗口1"); Thread t12 = new Thread(run, "窗口2"); Thread t13 = new Thread(run, "窗口3");
t11.start(); t12.start(); t13.start();
try { Thread.sleep(1000*20); System.exit(0); } catch (InterruptedException e) { e.printStackTrace(); } }
}
|
线程同步类
线程安全的类
StringBuffer
Vector
- 从Java2平台v1.2开始,该类改进了List接口,使其成为lava Collections Framework的成员。与新的集合实现不同,Vector被同步。如果不需要线程安全的实现,建议使用ArrayList代替Vector
Hashtable
- 该类实现了一个哈希表,它将键映射到值。任何非ul对象都可以用作键或者值
- 从Java2平台v1.2开始,该类进行了改进,实现了Map接口,使其成为ava Collections Framework的成员。与新的集合实现不同,Hashtable被同步。如果不需要线程安全的实现,建议使用HashMap代替Hashtable
代码
package 基础知识.进程和线程.A7_线程同步类;
import java.util.*;
public class RunsLei {
public static void main(String[] args) {
StringBuffer sb1 = new StringBuffer(); StringBuilder sb2 = new StringBuilder();
Vector<String> ve = new Vector<>(); ArrayList<String> list = new ArrayList<>();
Hashtable<String, String> ht = new Hashtable<>(); HashMap<String, String> hm = new HashMap<>();
List<String> array = Collections.synchronizedList(new ArrayList<String>()); Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());
}
}
|
Lock锁
Lock锁
虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,
为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的璥对象Lock
Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作
Lock中提供了获得锁和释放锁的方法
- void locko():获得锁
- void unlock():释放锁
Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化
ReentrantLock的构造方法
- ReentrantLockO:创建一个ReentrantLock的实例
代码
package 基础知识.进程和线程.A8_Lock锁;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;
public class MyRunnable implements Runnable { private int tick = 100; private Lock lock = new ReentrantLock();
@Override public void run() { while (true) {
try { lock.lock(); if (tick > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":正在出售第" + tick + "张票"); tick--; } }finally{ lock.unlock(); }
} } }
public class TestLock { public static void main(String[] args) { MyRunnable mr = new MyRunnable(); Thread t1 = new Thread(mr,"窗口1"); Thread t2 = new Thread(mr,"窗口2"); Thread t3 = new Thread(mr,"窗口3"); t1.start(); t2.start(); t3.start(); } }
|
wait // notify
生产者消费者案例
代码启动
public class BoxDame {
public static void main(String[] args) { Box box = new Box(); 生产者 s = new 生产者(box); 消费者 x = new 消费者(box); Thread ts = new Thread(s,"生产者"); Thread tx = new Thread(x,"消费者"); ts.start(); tx.start(); } }
|
Box 奶箱类
package 基础知识.进程和线程.A9_生产者和消费者.生产者消费者案例;
public class Box { private int make;
private boolean isMake = false;
public synchronized void put(int make) { if (isMake) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } }
this.make = make; System.out.println("送奶工将第" + make + "放入了奶箱"); this.isMake = true;
notifyAll(); }
public synchronized void get() { if (!isMake) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } }
System.out.println("消费者获取了第" + make + "瓶牛奶\n"); this.isMake = false;
notifyAll(); }
}
|
生产者
package 基础知识.进程和线程.A9_生产者和消费者.生产者消费者案例;
public class 生产者 implements Runnable{ private Box box;
public 生产者(Box box) { this.box = box; }
@Override public void run() { for (int i = 1; i <= 30 ; i++) { box.put(i); } } }
|
消费者
package 基础知识.进程和线程.A9_生产者和消费者.生产者消费者案例;
public class 消费者 implements Runnable{ private Box box;
public 消费者(Box box) { this.box = box; }
@Override public void run() { while (true){ box.get(); } } }
|
Thread 与 Runnable
比较
多线程 |
实现方法 |
实现方式1 |
继承Thread重写run方法 |
实现方式2 |
实现Runnable接口重写run方法 |
单词复习
单词 |
解释 |
Thread |
线程 |
start |
起始 |
getPriority |
获取线程调度 |
setPriority |
设置线程调度 |
sleep |
休眠 暂停 |
join |
等待线程死亡 |
setDaemon |
设置守护 线程 |
Runnable |
/线程接口 |
synchronized |
同步化 |
Vector |
List集合 同步化 |
Hashtable |
Map集合 同步化 |
Lock |
锁 接口 |
ReentrantLock |
重入锁 实现 |
lock |
上锁 |
unlock |
开锁 |
wait |
等待 |
notify |
通知 /唤醒等待 |