1.基本概念
进程:是一个正在执行的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元
线程:就是进程中的一个独立的控制单元,线程在控制着进程的执行
一个进程中至少有一个线程,线程有名称,从0开始,比如:Thread-0,Thread-1,主线程的名称为main
获取当前线程名称有两种:
Thread.currentThread() 结果为Thread[Thread-0,5,main],Thread[Thread-1,5,main]
this.getName() 结果为Thread-0,Thread-1
Thread.currentThread().getName() 结果为Thread-0,Thread-1
比如:
JVM启动时会有一个进程java.exe
该进程至少一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中,该进程称之为主线程
拓展:其实更细节说明jvm,jvm启动不止一个线程,还有负责垃圾回收机制的线程
2.状态
1. 新建状态(New):新创建了一个线程对象。
2. 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3. 运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4. 阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5. 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
多线程状态的内容转自haung_xw的博客 http://blog.csdn.net/huang_xw/article/details/7316354
3.实现方法
a.继承Thread类
步骤:
1.定义类继承Thread
2.复写Thread类中的run方法。目的:将自定义代码存储在run方法中,让线程运行
3.调用线程的start方法。作用:启动线程和调用run方法
public class Demo extends Thread{
public void run(){
for(int i=0;i<5;i++){
System.out.println("自定义线程"+i);
}
}
public static void main(String[] args) {
Demo demo = new Demo();
demo.start();
for(int i=0;i<5;i++){
System.out.println("主线程"+i);
}
}
}
发现运行结果每一次都不同,因为多个线程都获取cpu的执行权。cpu执行到谁,谁就运行,明确一点,在某个时刻,只能有一个程序在运行,(多核除外)cpu在做着快速的切换,以达到看上去是同时运行的效果
简单的卖票程序,多个窗口同时买票,ticketCount用static修饰,让多个线程共享票数
代码示例:
public class Ticket extends Thread{
private static int ticketCount = 5; //一般不用static,因为生命周期太长
public void run(){
while(true){
if(ticketCount>0){
System.out.println(Thread.currentThread().getName()+"..."+ticketCount--);
}
}
}
public static void main(String[] args) {
Ticket ticket1 = new Ticket();
Ticket ticket2 = new Ticket();
Ticket ticket3 = new Ticket();
Ticket ticket4 = new Ticket();
ticket1.start();
ticket2.start();
ticket3.start();
ticket4.start();
}
}
因为static修饰共享,生命周期太长了,那当把static去掉后,用另一种思考方式,即只有ticket1,并且用start方法启动多次是不是可以呢?
代码示例:
public class Ticket extends Thread{
private int ticketCount = 5;
public void run(){
while(true){
if(ticketCount>0){
System.out.println(Thread.currentThread().getName()+"..."+ticketCount--);
}
}
}
public static void main(String[] args) {
Ticket ticket1 = new Ticket();
//Ticket ticket2 = new Ticket();
//Ticket ticket3 = new Ticket();
//Ticket ticket4 = new Ticket();
ticket1.start();
ticket1.start();
ticket1.start();
ticket1.start();
}
}
<span style="font-size:14px;">
</span>
start方法调用一个已经启动的线程,系统会抛出 IllegalThreadStateException 异常,因为不可以多次启动一个线程,解决方法就是第二种方法实现Runable接口
b.实现Runable接口
出现的原因:
因为当使用第一种方式即继承Thread类时,而同时又要继承其他类时,则出现所继承现象,而java不支持多继承,所以通过第二种方式,实现Runable接口类完成多线程操作
步骤:
-
定义类实现Runable接口
-
覆盖Runable接口中的run方法,将线程要运行的代码存放在run方法中
-
通过Thread类建立线程对象
-
将Runable接口的子类对象作为实际参数传递给Thread类的构造函数
为什么要将Runable接口的子类对象要传递给Thread的构造函数,因为,自定义的run方法所需的对象是Runable接口的子类对象,所以要让线程去指定对象的run方法,就必须明确该run方法所属对象
-
调用Thread类的start方法开启线程并调用Runable接口子类的run方法
public class Ticket implements Runnable{
private int ticketCount = 5;
public void run(){
while(true){
if(ticketCount>0){
System.out.println(Thread.currentThread().getName()+"..."+ticketCount--);
}
}
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread ticket1 = new Thread(ticket);
Thread ticket2 = new Thread(ticket);
Thread ticket3 = new Thread(ticket);
Thread ticket4 = new Thread(ticket);
ticket1.start();
ticket2.start();
ticket3.start();
ticket4.start();
}
}
上面的结果是顺利的情况下产生的,假如多个线程在执行完 if(ticketCount > 0)语句后线程挂起,即cpu不执行当前线程,也就是不执行打印票数输出语句,则当多个暂挂线程苏醒后,会执行打印语句,从而产生0,-1,-2等错票和重票。为了实现效果,故意采用Thread.sleep()语句让线程睡眠,让多个线程挂起,产生错票效果,代码如下:
public class Ticket implements Runnable{
private int ticketcount = 5;
public void run(){ //InterruptedException异常不能抛,因为接受的是接口
while(true){
if(ticketcount>0){
try{
Thread.sleep(20);
}catch(InterruptedException e){
}
System.out.println(Thread.currentThread().getName()+"..."+ticketcount--);
}
}
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread ticket1 = new Thread(ticket);
Thread ticket2 = new Thread(ticket);
Thread ticket3 = new Thread(ticket);
Thread ticket4 = new Thread(ticket);
ticket1.start();
ticket2.start();
ticket3.start();
ticket4.start();
}
}
问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行一部分,还没有执行完,另一个线程就参与进来执行,导致共享数据错误
解决方法:
对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行
Java对于多线程安全问题提供了专业的解决方法,就是同步代码块
4.同步代码块
synchronized(对象){
需要被同步的代码
}
对象如同锁,持有锁的线程可以在同步中执行
没有持有锁的线程即使获得了cpu的执行权,也进不去,因为没有获取锁
同步的前提:
1.必须要有两个或者两个以上的线程
2.必须是多个线程使用同一个锁
必须保证同步中只能有一个线程在运行
好处:解决了多线程的安全问题
弊端:多个线程需要判断锁,较为浪费资源
代码如下:
public class Ticket implements Runnable{
private int ticketcount = 5;
Object obj = new Object();
public void run(){ //InterruptedException异常不能抛,因为接受的是接口
while(true){
synchronized (obj) {
if(ticketcount>0){
try{
Thread.sleep(20);
}catch(InterruptedException e){
}
System.out.println(Thread.currentThread().getName()+"..."+ticketcount--);
}
}
}
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread ticket1 = new Thread(ticket);
Thread ticket2 = new Thread(ticket);
Thread ticket3 = new Thread(ticket);
Thread ticket4 = new Thread(ticket);
ticket1.start();
ticket2.start();
ticket3.start();
ticket4.start();
}
}
5.同步函数
银行有一个金库
有两个储户分别存300元,每次存储100元,存3次
明确哪些语句需要同步:
1.明确哪些代码是多线程运行的代码
2.明确共享数据
3.明确多线程运行代码中哪些语句是操作共享数据
既然同步代码块是封装代码,函数也是封装代码,那直接让函数具备同步性(同步函数),同样也能实现效果。
class Bank{
private int sum;
//Object object = new Object();
public synchronized void add(int n){ //可以抛出异常
//synchronized (object) {
sum += n;
try {
Thread.sleep(10);//刻意让线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sum"+sum);
//}
}
}
class Customer implements Runnable{
private Bank bank = new Bank();
public void run(){
for(int i=0;i<3;i++){
bank.add(100);
}
}
}
public class BankDemo{
public static void main(String[] args) {
Customer customer = new Customer();
Thread thread = new Thread(customer);
Thread thread2 = new Thread(customer);
thread.start();
thread2.start();
}
}
注意*:使用同步函数时要注意函数封装的代码,不能盲目直接把函数加一个synchronized修饰符就以为可以了。
比如下面的例子:
public class Ticket implements Runnable{
private int ticketcount = 5;
//Object obj = new Object();
public synchronized void run(){ //InterruptedException异常不能抛,因为接受的是接口
while(true){
//synchronized (obj) {
if(ticketcount>0){
try{
Thread.sleep(20);
}catch(InterruptedException e){
}
System.out.println(Thread.currentThread().getName()+"..."+ticketcount--);
}
//}
}
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread ticket1 = new Thread(ticket);
Thread ticket2 = new Thread(ticket);
Thread ticket3 = new Thread(ticket);
Thread ticket4 = new Thread(ticket);
ticket1.start();
ticket2.start();
ticket3.start();
ticket4.start();
}
}
会发现只有0线程在运行,为什么?
原因:没搞清楚要同步的代码是哪些,run方法中的while(true) 语句不需要同步,当线程0获取锁,进来后就无限循环打印,直至把票数打印完。
解决方法:把要同步的代码单独封装到一个函数里,然后将函数变为同步函数即可。
public class Ticket implements Runnable{
private int ticketcount = 5;
public void run(){ //InterruptedException异常不能抛,因为接受的是接口
while(true){
show();
}
}
public synchronized void show(){
if(ticketcount>0){
try{
Thread.sleep(20);
}catch(InterruptedException e){
}
System.out.println(Thread.currentThread().getName()+"..."+ticketcount--);
}
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread ticket1 = new Thread(ticket);
Thread ticket2 = new Thread(ticket);
Thread ticket3 = new Thread(ticket);
Thread ticket4 = new Thread(ticket);
ticket1.start();
ticket2.start();
ticket3.start();
ticket4.start();
}
}
到这里分析一下锁的问题,前面用同步代码块时使用的锁是Object类的对象obj,而同步函数的锁是什么?
函数需要被对象调用,那么函数都有一个所属对象引用,就是this。所以同步函数使用的锁是this
下面通过程序验证:
通过两个线程来买票,一个线程在同步代码块中,一个线程在同步函数中,都执行买票动作。
public class Ticket implements Runnable{
private int ticketcount = 5;
Object obj = new Object();
boolean flag = true;
public void run(){ //InterruptedException异常不能抛,因为接受的是接口
if(flag == true){
while(true){
synchronized (obj) {
if(ticketcount>0){
try{
Thread.sleep(20);
}catch(InterruptedException e){
}
System.out.println(Thread.currentThread().getName()+"..."+ticketcount--+"同步代码块");
}
}
}
}
else{
while(true){
show();
}
}
}
public synchronized void show(){
if(ticketcount>0){
try{
Thread.sleep(20);
}catch(InterruptedException e){
}
System.out.println(Thread.currentThread().getName()+"..."+ticketcount--+"同步函数");
}
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread ticket1 = new Thread(ticket);
Thread ticket2 = new Thread(ticket);
//Thread ticket3 = new Thread(ticket);
//Thread ticket4 = new Thread(ticket);
ticket1.start();
ticket.flag = false;
ticket2.start();
//ticket3.start();
//ticket4.start();
}
}
通过结果分析,只有同步函数的线程在运行,原因:主线程中执行完ticket.start()时,启动了线程,但是可能处于临时状态,此时主线程继续执行,把接下来的代码
ticket.flag = false;
ticket2.start();
都执行完后,此时flag=false,所以一直都在同步函数中运行。
解决方法:在ticket.start();代码后加上
try{
Thread.sleep(10);
}catch(Exception e){
}
让主线程睡眠,即可解决。可是会发现输出结果还是有问题,出现了0号票
原因:同步代码块和同步函数两者用的锁不一样,同步代码块用的锁是obj,而同步函数用的锁是this,所以会出现安全隐患,打印出0号票
解决方法:使用同一把锁this即可。不用obj,因为只有同步代码块中才用对象obj作为锁,而同步函数是默认为this锁。
public class Ticket implements Runnable{
private int ticketcount = 5;
Object obj = new Object();
boolean flag = true;
public void run(){ //InterruptedException异常不能抛,因为接受的是接口
if(flag == true){
while(true){
synchronized (this) {
if(ticketcount>0){
try{
Thread.sleep(20);
}catch(InterruptedException e){
}
System.out.println(Thread.currentThread().getName()+"..."+ticketcount--+"同步代码块");
}
}
}
}
else{
while(true){
show();
}
}
}
public synchronized void show(){ //使用this锁
if(ticketcount>0){
try{
Thread.sleep(20);
}catch(InterruptedException e){
}
System.out.println(Thread.currentThread().getName()+"..."+ticketcount--+"同步函数");
}
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread ticket1 = new Thread(ticket);
Thread ticket2 = new Thread(ticket);
//Thread ticket3 = new Thread(ticket);
//Thread ticket4 = new Thread(ticket);
ticket1.start();
try{
Thread.sleep(10);
}catch(Exception e){
}
ticket.flag = false;
ticket2.start();
//ticket3.start();
//ticket4.start();
}
}
6.静态同步函数
public class Ticket implements Runnable{
private static int ticketcount = 100;
Object obj = new Object();
boolean flag = true;
public void run(){ //InterruptedException异常不能抛,因为接受的是接口
if(flag == true){
while(true){
synchronized (Ticket.class) {
if(ticketcount>0){
try{
Thread.sleep(20);
}catch(InterruptedException e){
}
System.out.println(Thread.currentThread().getName()+"..."+ticketcount--+"同步代码块");
}
}
}
}
else{
while(true){
show();
}
}
}
public static synchronized void show(){ //使用Class对象锁
if(ticketcount>0){
try{
Thread.sleep(20);
}catch(InterruptedException e){
}
System.out.println(Thread.currentThread().getName()+"..."+ticketcount--+"同步函数");
}
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread ticket1 = new Thread(ticket);
Thread ticket2 = new Thread(ticket);
//Thread ticket3 = new Thread(ticket);
//Thread ticket4 = new Thread(ticket);
ticket1.start();
try{
Thread.sleep(10);
}catch(Exception e){
}
ticket.flag = false;
ticket2.start();
//ticket3.start();
//ticket4.start();
}
}
7.懒汉式的多线程安全问题
class Single{
private Single(){};
private static Single single = null;
public static synchronized Single getInstance(){
if(single == null){
single = new Single();
}
return single;
}
}
但是会发现上面的代码不够好,因为不管对象是否为null都要判断锁。为了减少判断锁的次数,把代码优化后如下:
class Single{
private Single(){};
private static Single single = null;
public static Single getInstance(){
if(single == null){
synchronized (Single.class) {
if(single == null){
single = new Single();
}
}
}
return single;
}
}
8.死锁
class Test implements Runnable{
private boolean flag;
Test(boolean flag){
this.flag = flag;
}
public void run(){
if(flag == true){
synchronized (MyLock.locka) {
System.out.println("if locka");
synchronized (MyLock.lockb) {
System.out.println("if lockb");
}
}
}
else{
synchronized (MyLock.lockb) {
System.err.println("else lockb");
synchronized (MyLock.locka) {
System.out.println("else locka");
}
}
}
}
}
class MyLock{
static Object locka = new Object();
static Object lockb = new Object();
}
public class DeadLockTest{
public static void main(String[] args) {
Thread t1 = new Thread(new Test(true));
Thread t2 = new Thread(new Test(false));
t1.start();
t2.start();
}
}
9.线程间通信
class Res{
String name;
String sex;
}
class Input implements Runnable{
private Res r;
Input(Res r) {
this.r = r;
}
public void run(){
int x = 0;
while(true){
if(x == 0){
r.name = "小强";
r.sex = "男";
}
else{
r.name = "xaiohong";
r.sex = "women";
}
x = (x+1)%2;
}
}
}
class Ouput implements Runnable{
private Res r;
Ouput(Res r){
this.r = r;
}
public void run(){
while(true){
System.out.println(r.name+"..."+r.sex);
}
}
}
public class InputOuputDemo{
public static void main(String[] args) {
Res r = new Res();
Input in = new Input(r);
Ouput out = new Ouput(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
class Res{
String name;
String sex;
}
class Input implements Runnable{
private Res r;
Input(Res r) {
this.r = r;
}
public void run(){
int x = 0;
while(true){
if(x == 0){
r.name = "小强";
r.sex = "男";
}
else{
r.name = "xaiohong";
r.sex = "women";
}
x = (x+1)%2;
}
}
}
class Ouput implements Runnable{
private Res r;
Ouput(Res r){
this.r = r;
}
public void run(){
while(true){
System.out.println(r.name+"..."+r.sex);
}
}
}
public class InputOuputDemo{
public static void main(String[] args) {
Res r = new Res();
Input in = new Input(r);
Ouput out = new Ouput(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
10.生产者消费者
a.一对一
为了满足这样一个需求就是:Input中复制一次,Ouput就输出一次。class Res{
String name;
String sex;
boolean flag = false;
}
class Input implements Runnable{
private Res r;
Input(Res r) {
this.r = r;
}
public void run(){
int x = 0;
while(true){
synchronized (r) {
if(r.flag == true){
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(x == 0){
r.name = "小强";
r.sex = "男";
}
else{
r.name = "xaiohong";
r.sex = "women";
}
x = (x+1)%2;
r.flag = true;
r.notify();
}
}
}
}
class Output implements Runnable{
private Res r;
Output(Res r){
this.r = r;
}
public void run(){
while(true){
synchronized (r) {
if(r.flag == false){
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(r.name+"..."+r.sex);
r.flag = false;
r.notify();
}
}
}
}
public class InputOutputDemo{
public static void main(String[] args) {
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
class Res{
private String name;
private String sex;
private boolean flag = false;
public synchronized void set(String name,String sex){
if(flag == true){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name;
this.sex = sex;
flag = true;
this.notify();
}
public synchronized void out(){
if(flag == false){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(name+"..."+sex);
flag = false;
this.notify();
}
}
class Input implements Runnable{
private Res r;
Input(Res r) {
this.r = r;
}
public void run(){
int x = 0;
while(true){
if(x == 0){
r.set("小强", "男");
}
else{
r.set("xiaohong", "women");
}
x = (x+1)%2;
}
}
}
class Output implements Runnable{
private Res r;
Output(Res r){
this.r = r;
}
public void run(){
while(true){
r.out();
}
}
}
public class InputOutputDemo{
public static void main(String[] args) {
Res r = new Res();
new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
/*
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
*/
}
}
b.多对多
代码示例:class Res{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name){
if(flag == true){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name+"..."+count++;
System.out.println(Thread.currentThread().getName()+"...生产者"+this.name);
flag = true;
this.notify();
}
public synchronized void out(){
if(flag == false){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"......消费者"+this.name);
flag = false;
this.notify();
}
}
class Producer implements Runnable{
private Res r;
public Producer(Res r) {
this.r = r;
}
public void run() {
while(true){
r.set("+商品+");
}
}
}
class Consumer implements Runnable{
private Res r;
public Consumer(Res r) {
this.r = r;
}
public void run(){
while(true){
r.out();
}
}
}
public class ProducerConsumerDemo{
public static void main(String[] args) {
Res r = new Res();
Producer producer = new Producer(r);
Consumer consumer = new Consumer(r);
Thread t1 = new Thread(producer);
Thread t2 = new Thread(producer);
Thread t3 = new Thread(consumer);
Thread t4 = new Thread(consumer);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
出现了生产2次,只消费一次的问题
class Res{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name){
while(flag == true){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name+"..."+count++;
System.out.println(Thread.currentThread().getName()+"...生产者"+this.name);
flag = true;
this.notifyAll();
}
public synchronized void out(){
while(flag == false){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"......消费者"+this.name);
flag = false;
this.notifyAll();
}
}
class Producer implements Runnable{
private Res r;
public Producer(Res r) {
this.r = r;
}
public void run() {
while(true){
r.set("+商品+");
}
}
}
class Consumer implements Runnable{
private Res r;
public Consumer(Res r) {
this.r = r;
}
public void run(){
while(true){
r.out();
}
}
}
public class ProducerConsumerDemo{
public static void main(String[] args) {
Res r = new Res();
Producer producer = new Producer(r);
Consumer consumer = new Consumer(r);
Thread t1 = new Thread(producer);
Thread t2 = new Thread(producer);
Thread t3 = new Thread(consumer);
Thread t4 = new Thread(consumer);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
10.生产者消费者(jdk1.5升级版)
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Res{
private String name;
private int count = 1;
private boolean flag = false;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void set(String name) throws InterruptedException{
try{
lock.lock(); //加锁
while(flag == true){
condition.await(); //替换wait()
}
this.name = name+"..."+count++;
System.out.println(Thread.currentThread().getName()+"...生产者"+this.name);
flag = true;
condition.signalAll(); //替换notifyAll()
}
finally{
lock.unlock(); //释放锁
}
}
public void out() throws InterruptedException{
try{
lock.lock(); //加锁
while(flag == false){
condition.await(); //替换wait()
}
System.out.println(Thread.currentThread().getName()+"......消费者"+this.name);
flag = false;
condition.signalAll(); //替换notifyAll()
}
finally{
lock.unlock(); //释放锁
}
}
}
class Producer implements Runnable{
private Res r;
public Producer(Res r) {
this.r = r;
}
public void run() {
while(true){
try {
r.set("+商品+");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable{
private Res r;
public Consumer(Res r) {
this.r = r;
}
public void run(){
while(true){
try {
r.out();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ProducerConsumerDemo{
public static void main(String[] args) {
Res r = new Res();
Producer producer = new Producer(r);
Consumer consumer = new Consumer(r);
Thread t1 = new Thread(producer);
Thread t2 = new Thread(producer);
Thread t3 = new Thread(consumer);
Thread t4 = new Thread(consumer);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Res{
private String name;
private int count = 1;
private boolean flag = false;
private Lock lock = new ReentrantLock();
private Condition condition_pro = lock.newCondition();
private Condition condition_con = lock.newCondition();
public void set(String name) throws InterruptedException{
try{
lock.lock(); //加锁
while(flag == true){
condition_pro.await(); //替换wait()
}
this.name = name+"..."+count++;
System.out.println(Thread.currentThread().getName()+"...生产者"+this.name);
flag = true;
condition_con.signalAll(); //替换notifyAll()
}
finally{
lock.unlock(); //释放锁
}
}
public void out() throws InterruptedException{
try{
lock.lock(); //加锁
while(flag == false){
condition_con.await(); //替换wait()
}
System.out.println(Thread.currentThread().getName()+"......消费者"+this.name);
flag = false;
condition_pro.signalAll(); //替换notifyAll()
}
finally{
lock.unlock(); //释放锁
}
}
}
class Producer implements Runnable{
private Res r;
public Producer(Res r) {
this.r = r;
}
public void run() {
while(true){
try {
r.set("+商品+");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable{
private Res r;
public Consumer(Res r) {
this.r = r;
}
public void run(){
while(true){
try {
r.out();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ProducerConsumerDemo{
public static void main(String[] args) {
Res r = new Res();
Producer producer = new Producer(r);
Consumer consumer = new Consumer(r);
Thread t1 = new Thread(producer);
Thread t2 = new Thread(producer);
Thread t3 = new Thread(consumer);
Thread t4 = new Thread(consumer);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
11.Thread线程类方法
前面讲了start(),wait(),notify(),notifyAll(),sleep()方法,下面讲解其他方法a.中断线程
如何停止线程?
只有一种,run方法结束
开启多线程运行,运行代码通常是循环结构
只要控制循环,就可以让run方法结束,也就是线程结束
代码示例:
class StopThread implements Runnable{
private boolean flag = true;
public synchronized void run(){
while(flag == true){
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeFlag(){
flag = false;
}
}
public class StopThreadDemo{
public static void main(String[] args) {
StopThread stopThread = new StopThread();
Thread t1 = new Thread(stopThread);
Thread t2 = new Thread(stopThread);
t1.start();
t2.start();
int num = 0;
while(true){
if(num++ == 5){
stopThread.changeFlag();
break;
}
System.out.println(Thread.currentThread().getName()+"..."+num);
}
}
}
当线程处于冻结状态就不会读取到标记,那么线程就不会结束
当没有指定的方式让冻结的线程恢复到运行状态时,这时就需要对冻结进行清除
强制将线程恢复到运行状态来,这样就可以操作标记让线程结束
Thread类提供该方法 interrupt();
class StopThread implements Runnable{
private boolean flag = true;
public synchronized void run(){
while(flag == true){
try {
wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
flag = false; //interrupt后还是回去再等待,这句代码作用是让run方法真正结束
}
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeFlag(){
flag = false;
}
}
public class StopThreadDemo{
public static void main(String[] args) {
StopThread stopThread = new StopThread();
Thread t1 = new Thread(stopThread);
Thread t2 = new Thread(stopThread);
t1.start();
t2.start();
int num = 0;
while(true){
if(num++ == 5){
//stopThread.changeFlag();
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"..."+num);
}
}
}
b.守护线程
当线程设置为守护线程时,其他线程运行结束,线程将自动结束,不用强制用interrupt结束。方法为setDaemon(true);
代码示例:
class StopThread implements Runnable{
private boolean flag = true;
public synchronized void run(){
while(flag == true){
try {
wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
flag = false; //interrupt后还是回去再等待,这句代码作用是让run方法真正结束
}
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeFlag(){
flag = false;
}
}
public class StopThreadDemo{
public static void main(String[] args) {
StopThread stopThread = new StopThread();
Thread t1 = new Thread(stopThread);
Thread t2 = new Thread(stopThread);
t1.setDaemon(true); //t1设置为守护线程
t2.setDaemon(true); //t2设置为守护线程
t1.start();
t2.start();
int num = 0;
while(true){
if(num++ == 5){
//stopThread.changeFlag();
//t1.interrupt();
//t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"..."+num);
}
}
}
b.抢夺线程
方法为join(),把主线程的cpu执行权抢过来。执行完线程再执行完其他线程。代码示例:
class Demo implements Runnable{
public void run(){
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"..."+i);
}
}
}
public class JoinDemo{
public static void main(String[] args)throws Exception{
Demo d = new Demo();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t1.join();
t2.start();
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"..."+i);
}
System.out.println("over");
}
}
c.让步线程
方法为yield()
就是说当一个线程使用了这个方法之后,它就会把自己CPU执行的时间让掉,让自己或者其它的线程运行。相当于轮到自己了,却要和别的线程竞赛。
代码示例:
class Demo implements Runnable{
public void run(){
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"..."+i);
Thread.yield();
}
}
}
public class JoinDemo{
public static void main(String[] args)throws Exception{
Demo d = new Demo();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t2.start();
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"..."+i);
}
System.out.println("over");
}
}
d.优先级线程
方法为setPriority(Thread.MAX_PRIORITY); 代表最高优先级setPriority(Thread.MIN_PRIORITY); 代表最低优先级
优先级只是概率上增加或者减少,而不是一定执行,最终还是由cpu决定
代码示例:
class Demo implements Runnable{
public void run(){
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"..."+i);
}
}
}
public class JoinDemo{
public static void main(String[] args)throws Exception{
Demo d = new Demo();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t1.setPriority(Thread.MAX_PRIORITY); //设置优先级最高
t2.start();
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"..."+i);
}
System.out.println("over");
}
}