多线程同步

回顾

1 进程:正在运行的程序,操作系统通过进程Id区分不同进程。2 线程:进程中的一条执行路径。一个进程中可以包含多个线程,至少有一个。3 区别:a.一个程序运行后至少有一个进程b.一个进程可以包含多个线程,但是至少需要有一个线程,否则这个进程是没有意义的c.进程间不能共享资源,但线程之间可以d.系统创建进程需要为该进程重新分配系统资源,而创建线程则容易的多,因此使用线程实现多任务并发比多进程的效率高
4 多线程的创建(1)继承Thread ,重写run方法(2)实现Runnable接口(3)实现Callable<V>接口  有返回值,可以抛出异常,FutureTask<T>
5 线程的方法线程对象.setName(); 继承Thread类构造方法休眠Thread.sleep();线程对象.priority();线程对象.join();//加入合并线程对象.setDaemone(true);//后台线程  垃圾回收器Thread.yield();//让步线程对象.interrupt();//打断  打断所有能抛出InterruptException的线程6 声明周期
五个状态新生--->就绪---->运行---->阻塞----->死亡

今天任务

1.多线程访问临界资源1.1 多线程访问临界资源时的数据安全问题1.2 解决临界资源问题1.3 锁1.4 同步代码块1.5 同步方法1.6 ReentrantLock类
2.死锁
3.多线程在单例设计模式中的应用
4.线程的通信(难)4.1 原理4.2 实现

教学目标

1.了解多线程中临界资源问题产生的原因
2.掌握解决临界资源问题的方案
3.掌握锁的概念
4.掌握同步代码块和同步方法
5.了解ReentrantLock类的使用
6.掌握多线程在单例中的应用
7.了解死锁以及生产者与消费者设计模式

第一节 多线程访问临界资源

1.1 多线程访问临界资源时的数据安全问题
 临界资源 :多个线程同时访问的资源。产生原因:有多个线程在同时访问一个资源,如果一个线程在取值的过程中,时间片又被其他线程抢走了,临界资源问题就产生了演示:卖票案例
1.2 解决临界资源问题
 解决方案:一个线程在访问临界资源的时候,如果给这个资源“上一把锁”,这个时候如果其他线程也要访问这个资源,就得在“锁”外面等待。
1.3 锁
锁:任意的对象都可以被当做锁来使用
1.4 同步代码块

同步:Synchronized:有等待

异步:Asynchronized:没有等待,各执行各的

语法:synchronized(锁) {//需要访问临界资源的代码段}说明:a.程序走到代码段中,就用锁来锁住了临界资源,这个时候,其他线程不能执行代码段中的代码,只能在锁外边等待b.执行完代码段中的这段代码,会自动解锁。然后剩下的其他线程开始争抢cpu时间片c.一定要保证不同的线程看到的是同一把锁,否则同步代码块没有意义

​ 2.2.1 同步代码块使用

public class Ticket implements Runnable{// 需求:100张// 临界资源private int ticket = 100;@Overridepublic void run() {while (true) {//上锁synchronized(this){if (ticket < 1) {break;}System.out.println("售票员" + Thread.currentThread().getName() + "售出第"+ticket+"张票");ticket--;}}}
}
1.5 同步方法

​ 2.3.1 同步非静态方法

public class Ticket implements Runnable{// 需求:100张// 临界资源private int ticket = 100;@Overridepublic void run() {while (true) {if(!sale()){break;}}}public synchronized boolean sale(){//锁是thisif (ticket < 1) {return false;}System.out.println("售票员" + Thread.currentThread().getName() + "售出第"+ticket+"张票");ticket--;return true;}
}

​ 2.3.2 同步静态方法

public class Ticket implements Runnable{// 需求:100张// 临界资源private static int ticket = 100;@Overridepublic void run() {while (true) {if(!sale()){break;}}}public synchronized static boolean sale(){ //锁是 类.classif (ticket < 1) {return false;}System.out.println("售票员" + Thread.currentThread().getName() + "售出第"+ticket+"张票");ticket--;return true;}
}
1.6 ReentrantLock类(可重入锁)jdk1.5
 从jdk1.5之后加入新的接口 Lock,ReentrantLock是Lock接口的实现类。通过显式定义同步锁对象来实现同步,同步锁提供了比synchronized代码块更广泛的锁定操注意:最好将 unlock的操作放到finally块中通过使用ReentrantLock这个类来进行锁的操作,它实现了Lock接口,使用ReentrantLock可以显式地加锁、释放锁

​ 案例一:模拟售票

import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo01 {public static void main(String[] args) {Ticket res=new Ticket();Thread t0 = new Thread(res, "喜羊羊");Thread t1 = new Thread(res, "沸羊羊");Thread t2 = new Thread(res, "灰太狼");Thread t3 = new Thread(res, "小灰灰");t0.start();t1.start();t2.start();t3.start();}
}//票类
public class Ticket implements Runnable{// 需求:100张// 临界资源private int ticket = 100;// 定义一个ReentrantLock类的对象ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while (true) {//上锁lock.lock();if (count < 1) {break;}System.out.println("售票员" + Thread.currentThread().getName() + "售出第"+ticket+"张票");ticket--;//解锁// unlock()lock.unlock();//注意:lock()和unlock()都是成对出现的}}
}

​ 案例二:模拟银行卡存取钱

package com.qf.day20_4;public class BankCard {private double money;public double getMoney() {return money;}public void setMoney(double money) {this.money = money;}}
package com.qf.day20_4;
/*** 存取类* @author wgy**/
public class AddMoney implements Runnable{private BankCard card;public AddMoney(BankCard card) {this.card = card;}@Overridepublic void run() {for(int i=0;i<10;i++) {synchronized (card) {card.setMoney(card.getMoney()+1000);//钱加上System.out.println(Thread.currentThread().getName()+"存了1000,余额是:"+card.getMoney());}}}}
package com.qf.day20_4;public class SubMoney implements Runnable{private BankCard card;public SubMoney(BankCard card) {this.card = card;}@Overridepublic void run() {for(int i=0;i<10;i++) {synchronized (card) {if(card.getMoney()>=1000) {card.setMoney(card.getMoney()-1000);System.out.println(Thread.currentThread().getName()+"取了1000,余额是:"+card.getMoney());}else {System.out.println("余额不足");i--;}}}}
}public class Test {public static void main(String[] args) {//1创建卡BankCard card=new BankCard();//2创建存钱和取钱功能AddMoney add=new AddMoney(card);SubMoney sub=new SubMoney(card);//3创建线程对象Thread zhengshuai=new Thread(add,"帅帅");Thread benwei=new Thread(sub,"本伟");//4启动zhengshuai.start();benwei.start();}
}

第二节 死锁

​ 每个人都拥有其他人需要的资源,同时又等待其他人拥有的资源,并且每个人在获得所有需要的资源之前都不会放弃已经拥有的资源。

​ 当多个线程完成功能需要同时获取多个共享资源的时候可能会导致死锁

死锁的条件:

​ 1两个以上的线程

​ 2至少两个锁以上

​ 3同步中嵌套同步

/*
*锁
*/
public class Lock {public static Object locka=new Object();//第一个锁public static Object lockb=new Object();//第二个锁
}
/*
*男孩
*/
public class Boy extends Thread{@Overridepublic void run() {while (true) {synchronized (Lock.locka) {System.out.println("男孩拿着locka");synchronized (Lock.lockb) {System.out.println("男孩拿到lockb");System.out.println("男孩可以吃了....");}} }}
}
/** 女孩*/
public class Girl extends Thread{@Overridepublic void run() {while (true) {synchronized (Lock.lockb) {System.out.println("女孩拿着lockb");synchronized (Lock.locka) {System.out.println("女孩拿到了locka");System.out.println("女孩可以吃了...");}} }}
}
public static void main(String[] args) {Boy shaqiang=new Boy();Girl xiaofeng=new Girl();shaqiang.start();xiaofeng.start();}

第三节 多线程在单例中的应用

单例的实现方式:懒汉式和饿汉式其中,懒汉式是线程不安全的,当有多条线程同时访问单例对象时,则会出现多线程临界资源问题
单例实现步骤:1 私有化构造方法2 在类中创建对象3 通过公开的方法返回这个对象
3.1 多线程访问单例-饿汉式
package com.qf.day20_7;
/*** 单例模式* @author wgy**/
public class SingleTon {//1私有化构造方法private SingleTon() {}//2创建对象private static SingleTon instance=new SingleTon();//3公开的方法返回这个对象public static SingleTon getInstance() {return instance;}}package com.qf.day20_7;public class SingleTonThread extends Thread{@Overridepublic void run() {SingleTon singleTon=SingleTon.getInstance();System.out.println(singleTon.hashCode());}
}   package com.qf.day20_7;public class Test {public static void main(String[] args) {//      SingleTonThread s1=new SingleTonThread();
//      SingleTonThread s2=new SingleTonThread();
//      SingleTonThread s3=new SingleTonThread();
//      s1.start();
//      s2.start();
//      s3.start();Runnable r=new Runnable() {@Overridepublic void run() {SingleTon singleTon=SingleTon.getInstance();System.out.println(singleTon.hashCode());}};new Thread(r).start();new Thread(r).start();new Thread(r).start();}
}
3.2 多线程访问单例-懒汉式
/*** 单例* @author wgy**/
public class SingleTon {private SingleTon(){}private  static SingleTon singleTon;public static SingleTon getInstance() {if(singleTon==null) {//为了提高效率synchronized (SingleTon.class) {//判断锁的过程比较耗性能,为了提高效率if (singleTon == null) {singleTon = new SingleTon();}}}return singleTon;}}/*** 线程类* @author wgy**/
public class SingleTonThread extends Thread{@Overridepublic void run() {SingleTon singleTon=SingleTon.getInstance();System.out.println(singleTon.hashCode());}
}package com.qf.day20_6;public class Test {public static void main(String[] args) {//线程对象SingleTonThread s1=new SingleTonThread();SingleTonThread s2=new SingleTonThread();SingleTonThread s3=new SingleTonThread();//启动线程s1.start();s2.start();s3.start();}
}

第四节 线程的通信【生产者与消费者设计模式】

4.1 线程通信

需求:你和你朋友公用一张银行卡,你向卡中存钱,你朋友取钱,保证你存一笔,然后取一笔,再存一笔,再取一笔。

实现功能:使用线程通信。

在jdk1.5之前有三个方法实现线程通信:

wait(): 等待,线程执行这个方法进入等待队列(和锁有关,一个锁对应一个等待队列), 需要被唤醒

notify(): 通知唤醒,从等待队列中随机唤醒一个线程

notifyAll():全部唤醒,把等待队列中所有的线程都唤醒

代码实现

package com.qf.day20_8;public class BankCard {private double money;private boolean flag;// 标记 true  表示有钱, false没钱public double getMoney() {return money;}public void setMoney(double money) {this.money = money;}/**** 存取*/public synchronized void save() { //thiswhile(flag) {//true 有钱try {this.wait();//等待,释放了cpu,释放了锁 ,调用wait的对象是锁} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//等待}money=money+1000;System.out.println(Thread.currentThread().getName()+"存了1000,余额是:"+money);flag=true;//修改标记this.notifyAll();//唤醒取钱线程取取钱}/*** 取*/public synchronized void qu() {//thiswhile(flag==false) {try {this.wait();//等待  释放cpu和锁} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}money=money-1000;System.out.println(Thread.currentThread().getName()+"取了1000,余额是:"+money);//修改标记flag=false;//唤醒this.notifyAll();}}package com.qf.day20_8;
/*** 存取类* @author wgy**/
public class AddMoney implements Runnable{private BankCard card;public AddMoney(BankCard card) {this.card = card;}@Overridepublic void run() {for(int i=0;i<10;i++) {card.save();}}}package com.qf.day20_8;public class SubMoney implements Runnable{private BankCard card;public SubMoney(BankCard card) {this.card = card;}@Overridepublic void run() {for(int i=0;i<10;i++) {card.qu();}}}package com.qf.day20_8;public class Test {public static void main(String[] args) {//1创建卡BankCard card=new BankCard();//2创建存钱和取钱功能AddMoney add=new AddMoney(card);SubMoney sub=new SubMoney(card);//3创建线程对象Thread zhengshuai=new Thread(add,"帅帅");Thread dalang=new Thread(add, "大郎");Thread benwei=new Thread(sub,"本伟");Thread xiaolian=new Thread(sub,"金莲");//4启动zhengshuai.start();benwei.start();dalang.start();xiaolian.start();}
}
4.2 生产者与消费者设计模式原理
它描述的是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者可以从仓库中取走产品,解决生产者/消费者问题,我们需要采用某种机制保护生产者和消费者之间的同步同步问题核心在于:如何保证同一资源被多个线程并发访问时的完整性,常用的方法就是加锁,保证资源在任意时刻只被一个线程访问

画图分析:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-efNe08Lt-1575684811911)(生产者与消费者设计模式.png)]

4.3 实现

采用wait()、notify()和notifyAll()方法

wait():当缓冲区已满或空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行·是Object的方法·调用方式:对象.wait();·表示释放 对象 这个锁标记,然后在锁外边等待(对比sleep(),sleep是抱着锁休眠的)·等待,必须放到同步代码段中执行
notify():当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态·是Object的方法·调用方式:对象.notify();·表示唤醒 对象 所标记外边在等待的一个线程
notifyAll():全部唤醒·是Object的方法·调用方式:对象.notifyAll()·表示唤醒  对象 所标记外边等待的所有线程
/*
*面包
*/
public class Bread {private int id;private String productName;public Bread() {// TODO Auto-generated constructor stub}public Bread(int id, String productName) {super();this.id = id;this.productName = productName;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getProductName() {return productName;}public void setProductName(String productName) {this.productName = productName;}@Overridepublic String toString() {return "Bread [id=" + id + ", productName=" + productName + "]";}}
/** 面包容器*/
public class BreadCon {private Bread con;private boolean flag; ////放入面包public synchronized void input(Bread b){while(flag==true){try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}this.con=b;System.out.println(Thread.currentThread().getName()+"生产了"+b.getId());flag=true;this.notifyAll();}//吃面包public synchronized void output(){while(flag==false){try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}Bread b=con;con=null;System.out.println(Thread.currentThread().getName()+"消费了"+b.getId()+" 生产者:"+b.getProductName());flag=false;this.notifyAll();}
}
/** 生产面包类*/
public class Product implements Runnable{private BreadCon con;public Product(BreadCon con) {this.con=con;}@Overridepublic void run() {for(int i=1;i<=30;i++){Bread b=new Bread(i, Thread.currentThread().getName());this.con.input(b);}}
}
/** 消费面包*/
public class Consume implements Runnable{private BreadCon con;public Consume(BreadCon con) {this.con=con;}@Overridepublic void run() {for(int i=1;i<=30;i++){con.output();}}
}
public static void main(String[] args) {//1创建容器BreadCon con=new BreadCon();//2生产Product product=new Product(con);//3消费Consume consume=new Consume(con);//4线程对象Thread shaqiang=new Thread(product, "莎强");Thread xiaocang=new Thread(consume,"小苍");//5启动shaqiang.start();xiaocang.start();}

扩展:使用Jdk1.5 Lock优化生产者和消费者

package com.qf.day20_11;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 面包容器* @author wgy**/
public class BreadCon {private Bread con;private boolean flag;private Lock lock=new ReentrantLock();Condition proCondition=lock.newCondition();Condition conCondition=lock.newCondition();/*** 放入面包*/public  void input(Bread b) {lock.lock();try {while (flag) {try {proCondition.await();} catch (Exception e) {// TODO: handle exception}}con = b;System.out.println(Thread.currentThread().getName() + "生产了" + b.getId() + "面包");flag = true;conCondition.signal();} finally {lock.unlock();} }/*** 消费面包*/public  void output() {lock.lock();try {while (!flag) {try {conCondition.await();} catch (Exception e) {// TODO: handle exception}}Bread b = con;System.out.println(Thread.currentThread().getName() + "消费了" + b.getId() + "面包, 生产者名字:" + b.getProductName());con = null;flag = false;proCondition.signal();} finally {lock.unlock();}}}

扩展知识1:读写锁

ReadWriteLock接口:可以实现多个读线程同时读取数据,写线程需要互斥执行。

读|写 、写|写 需要互斥

读|读 不需要互斥

package com.qf.day13;import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReadWriteDemo {private int number=0;private ReadWriteLock lock=new ReentrantReadWriteLock();public void read() {lock.readLock().lock();try {System.out.println(Thread.currentThread().getName()+"读取了:"+number);} finally {lock.readLock().unlock();}}public void write(int number) {lock.writeLock().lock();try {System.out.println(Thread.currentThread().getName()+"写入了"+number);this.number=number;} finally {lock.writeLock().unlock();}}
}

测试类:

package com.qf.day13;import java.util.Random;public class Test {public static void main(String[] args) {ReadWriteDemo rw=new ReadWriteDemo();new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}rw.write(new Random().nextInt(100));}}).start();Runnable r=new Runnable() {@Overridepublic void run() {rw.read();     }};for(int i=0;i<100;i++) {new Thread(r).start();}}
}

扩展知识2:线程池

为什么需要线程池:

​ 例如有非常的多的任务需要多线程来完成,且每个线程执行时间不会太长,这样会频繁的创建和销毁线程。频繁创建和销毁线程会比较耗性能。如果有了线程池就不要创建更多的线程来完成任务,因为线程可以重用。

​ 线程池用维护者一个队列,队列中保存着处于等待(空闲)状态的线程。不用每次都创建新的线程。

和线程池相关的接口和类存在java.util.concurrent并发包中。

接口:

1 Executor:线程池的核心接口,负责线程的创建使用和调度的根接口

2 ExecutorService: Executor的子接口,线程池的主要接口, 提供基本功能。

3 ScheduledExecutorService: ExecutorService的子接口,负责线程调度的子接口。

实现类:

1 ThreadPoolExecutor:ExecutorService的实现类,负责线程池的创建使用。

2 ScheduledThreadPoolExecutor:继承 ThreadPoolExecutor,并实现 ScheduledExecutorService接口,既有线程池的功能,又具有线程调度功能。

3 Executors:线程池的工具类,负责线程池的创建。

​ newFixedThreadPool();创建固定大小的线程池。

​ newCachedThreadPool();创建缓存线程池,线程池大小没有限制。根据需求自动调整线程数量。

​ newSingleThreadExecutor();创建单个线程的线程池,只有一个线程。

​ newScheduledThreadPool();创建固定大小的线程池,可以延迟或定时执行任务。

案例一:使用线程池实现卖票

package com.qf.day13;public class Ticket implements Runnable{private int ticket=100;@Overridepublic void run() {while(true) {if(ticket<=0) {break;}System.out.println(Thread.currentThread().getName()+"卖第"+ticket+"张票");ticket--;}}}
package com.qf.day13;import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Test {public static void main(String[] args) {Ticket ticket=new Ticket();ExecutorService threadPool = Executors.newFixedThreadPool(4);for(int i=0;i<4;i++) {threadPool.submit(ticket);}threadPool.shutdown();System.out.println("主线程执行完毕........");}
}

案例二:线程池计算1-100的和,要求采用Callable接口

package com.qf.day13;import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;public class Test {public static void main(String[] args) throws Exception {ExecutorService threadPool = Executors.newFixedThreadPool(4);List<Future<Integer>> list=new ArrayList<>();for (int i = 0; i < 10; i++) {Future<Integer> future = threadPool.submit(new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 0; i <= 100; i++) {Thread.sleep(10);sum += i;}System.out.println(Thread.currentThread().getName() + "计算完毕");return sum;}});list.add(future);}threadPool.shutdown();System.out.println("主线程结束了。。。。");for (Future<Integer> fu : list) {int s = fu.get();System.out.println(s);}}
}

案例三:延迟执行任务

package com.qf.day13;import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;public class Test2 {public static void main(String[] args) throws Exception{ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);List<Future<Integer>> list=new ArrayList<>();for(int i=0;i<10;i++) {Future<Integer> future=threadPool.schedule(new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int ran=new Random().nextInt(100);System.out.println(Thread.currentThread().getName()+"...."+ran);return ran;}},3,TimeUnit.SECONDS);list.add(future);}threadPool.shutdown();System.out.println("主线程结束了...........");for (Future<Integer> future2 : list) {int n=future2.get();System.out.println(n);}}
}

总结

1 多线程访问临界资源数据安全问题?
2 解决安全问题同步 + 锁
3 同步代码块synchronized(metux){}锁:引用类型 ,唯一的
4 同步方法  方法的返回值前面 synchronized 非静态方法 锁:this静态方法 锁:类名.class5 可重入锁 ReentrantLockLock lock=new ReeentrantLock();lock.lock()try{}finally{lock.unlock();}
6 死锁 1多个锁 ,多个线程2同步中嵌套同步
7 单例模式优化懒汉式写法
8 线程通信Object中三个方法 wait(); 等待notifiy(); 唤醒notifyAll();唤醒所有的jdk1.5 Lock通信Conditon代替监视器方法

课前默写

1.分别使用继承Thread类和实现Runnable接口的方式创建线程2.设计程序,演示join方法的使用

作业

1.春运到了,某个火车站四个售票员出售某个车次最后100张车票的情形。
分析:火车票:  临界资源四个售票员:四个线程实例  , 出售车票:卖一张,车票就少一张2.使用线程安全的懒汉式写法。3.完善昨天的作业,模拟多个人通过一个山洞的模拟。这个山洞每次只能通过一个人,每个人通过山洞的时间为5秒,随机生成10个人,同时准备过此山洞,显示一下每次通过山洞人的姓名

面试题

1.多线程临界资源问题是如何产生的,该怎么解决是因为多个线程访问同一个资源,出现安全问题? 使用同步代码块  同步方法  ReentrantLock
2.简述生产者与消费者设计模式的实现原理1 同步2 线程间通信, wait(), notify()  notifyAll();
3.sleep()和wait()的区别?1>sleep休眠,自动唤醒,wait()等待一般需要别的线程唤醒,也可以设置等待时间,需要获的锁之后才能运行。2>sleep休眠只释放了cpu,没有释放锁, wait()cpu和锁都释放。
4.三个线程交替输出A B C ,输出20遍。
5.volitale关键字的作用?多个线程共享同一个变量,保证一个线程堆变量的修改,别的线程能理解看见。只能保证可见性和重排序,不能保证互斥。
6.i++操作是原子操作吗?i++;int temp=i;i=i+1;分析如下代码,指出问题原因?如何解决package com.qf.day13;public class Test3 {public static void main(String[] args) {Atomic atomic=new Atomic();for(int i=0;i<10;i++) {new Thread(atomic).start();}}
}class Atomic implements Runnable{int num=0;@Overridepublic void run() {try {Thread.sleep(200);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(num++);}}

notifiy(); 唤醒
notifyAll();唤醒所有的

 jdk1.5 Lock通信Conditon代替监视器方法

默写

1.分别使用继承Thread类和实现Runnable接口的方式创建线程2.设计程序,演示join方法的使用

作业

1.春运到了,某个火车站四个售票员出售某个车次最后100张车票的情形。
分析:火车票:  临界资源四个售票员:四个线程实例  , 出售车票:卖一张,车票就少一张2.使用线程安全的懒汉式写法。3.完善昨天的作业,模拟多个人通过一个山洞的模拟。这个山洞每次只能通过一个人,每个人通过山洞的时间为5秒,随机生成10个人,同时准备过此山洞,显示一下每次通过山洞人的姓名

作业答案关注 +私信哦

面试题

1.多线程临界资源问题是如何产生的,该怎么解决是因为多个线程访问同一个资源,出现安全问题? 使用同步代码块  同步方法  ReentrantLock
2.简述生产者与消费者设计模式的实现原理1 同步2 线程间通信, wait(), notify()  notifyAll();
3.sleep()和wait()的区别?1>sleep休眠,自动唤醒,wait()等待一般需要别的线程唤醒,也可以设置等待时间,需要获的锁之后才能运行。2>sleep休眠只释放了cpu,没有释放锁, wait()cpu和锁都释放。
4.三个线程交替输出A B C ,输出20遍。
5.volitale关键字的作用?多个线程共享同一个变量,保证一个线程堆变量的修改,别的线程能理解看见。只能保证可见性和重排序,不能保证互斥。
6.i++操作是原子操作吗?i++;int temp=i;i=i+1;分析如下代码,指出问题原因?如何解决package com.qf.day13;public class Test3 {public static void main(String[] args) {Atomic atomic=new Atomic();for(int i=0;i<10;i++) {new Thread(atomic).start();}}
}class Atomic implements Runnable{int num=0;@Overridepublic void run() {try {Thread.sleep(200);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(num++);}}

Java多线程同步和通信相关推荐

  1. java同步通信方式_java多线程同步与通信示例(synchronized方式)

    java多线程同步示例,来自<疯狂java讲义>.通过synchronized,wait(),notify(),notifyAll()实现多线程同步与通信.假设现在系统中有两个线程,这两个 ...

  2. Java多线程间的通信

    Java多线程间的通信 Java还提供了一种线程间通信的机制,这种通信通什么实现? wait,notify等机制    或使用pipeInputStream和pipeOutputStream 1. 线 ...

  3. Java多线程之线程通信之生产者消费者阻塞队列版

    Java多线程之线程通信之生产者消费者传统版和阻塞队列版 目录 线程通信之生产者消费者传统版 线程通信之生产者消费者阻塞队列版 1. 线程通信之生产者消费者传统版 题目: 一个初始值为零的变量,两个线 ...

  4. java 什么是线程同步,java多线程同步集合是什么?并发集合是什么?

    java中关于集合的内容也是十分丰富的,而且相关的知识点也是十分多的.多线程集合所涵盖的范围是十分广阔的.今天就来为大家介绍一下,java多线程同步集合是什么以及并发集合是什么?一起来看看吧. 首先我 ...

  5. Java多线程同步机制

    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个 ...

  6. java多线程同步与死锁_浅析Java多线程中的同步和死锁

    Value Engineering 1基于Java的多线程 多线程是实现并发机制的一种有效手段,它允许编程语言在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间相互独立,且与进程一样拥有独立 ...

  7. Android 价值千万java多线程同步 lt;五CountDownLatch(计数器)和Semaphore(信号量)

    1).Android 价值千万   java线程专题:Wait&notify&join&Yield http://blog.csdn.net/whb20081815/artic ...

  8. Java多线程同步之使用Lock实现车辆入库出库管理

    Java多线程同步之使用Lock实现车辆入库出库管理 个人笔记: 实现:车库有n个车位,现在有m辆车试图进入车库,每辆车停留随机秒数后离开 首先创建一个Garage车库类,Garage有空间属性和最大 ...

  9. (转) Java多线程同步与异步

    Java线程 同步与异步 线程池 1)多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线 程的处理的数据,而B线程又修改了A线程处理的数理.显然这是由于全局资源造成 ...

最新文章

  1. python中单双三引号区别_python基础题
  2. OpenCV:没有GUI的情况下使用OpenCV无缝克隆模块(附完整代码)
  3. php 加七天减七天,php实战第七天_PHP教程
  4. python appium自动化测试框架unittest_Appium基于Python unittest自动化测试 自动化测试框架 -- PO并生成html测试报告...
  5. 关于Oracle与MySQL的使用总结
  6. pandas将所0值修改为NaN
  7. 十七 Ajax校验用户名功能
  8. C++ STL 函数partial_sum的正确使用方法
  9. 体育类App原型制作分享-Onefootball
  10. 微信公众号开发框架 For Java —— wechatapi
  11. 什么是宽带薪酬?宽带薪酬系统如何实施?
  12. Actors编程模型
  13. java第六章十七题_Java语言面试题十七
  14. V4L2 驱动框架概览
  15. 机器自动翻译古文拼音 - 十大宋词 - 声声慢 寻寻觅觅 李清照
  16. ofbiz实战8——实验室预约管理系统功能介绍
  17. 4.17 使用阴影/高光命令解决图像曝光不足问题 [原创Ps教程]
  18. 解读wlk成就系统系列之:我亲爱的小松鼠们
  19. 苹果基带坏了怎么办_iPhone8/8plus无服务怎么办?
  20. 兀键和6键怎么判断_你们不会的大π键(高三党,基础较好)

热门文章

  1. 【手把手教你】Python金融财务分析
  2. 动态规划之双11的红包雨
  3. 巧用springboot微服务搭建一个网站
  4. 刚刚!知网开放个人查重服务,研究生学位论文3次免费,网友吐糟:「毕业了才开放」...
  5. jdk卸载?提示jdk已安装?两个方式解决
  6. 中国人民大学_《组织行为学》_13.领导风格:怎样获取团队认同?
  7. eval 函数 java_JavaScript eval()函数定义及使用方法详解
  8. html 配置超链接不可用,css如何设置超链接不可用?
  9. 2022安全员-A证考试题模拟考试题库及在线模拟考试
  10. 大麦哲伦星系中的一个新恒星诞生区 制造出强烈喷流冲击波