黑马程序员_多线程2

来源:互联网 发布:2013淘宝男装店铺排行 编辑:程序博客网 时间:2024/04/30 07:22

-----------------------------------------------------------------android培训java培训、期待与您交流! ---------------------------------------------------------------

1.      多线程的安全问题:synchronized(同步问题)

①      多线程同步代码块

②      多线程同步函数 :同步关键字作为修饰符修饰函数

同步代码块:

synchronized(对象)

{

       需要被同步的代码

}

同步的前提(重要)

1.      必须有两个或两个以上线程

2.      必须是多个线程使用同一个锁

同步代码块弊端:因为线程每次都要对锁进行判断,比较消耗资源(该消耗在使用允许范围内)

 

同步函数

当synchronized修饰函数时,并没有指定锁,其默认的锁为this

如果同步函数被static静态修饰时,因为静态方法中还没有this(即还没有对象),静态进内存中还没有本类对象,但是一定有该类对应的字节码文件对象-----即:类名.class 该对象的类型是Class,使用可以使用该类对象.clsss文件为锁

 

懒汉式的安全问题

//饿汉式class Single {private static final Single s = new Single();private Single(){}public static Single getInstance() {return s;}}
因为饿汉式在开始时就已经创建了Single实例,所以并不会出现多线程的安全问题

//懒汉式---存在多线程安全问题class Single {private static Single s = null;private Single() {}public static Single getInstance() {if(s == null)s = new Single();return s;}}
在多线程情况下,判断single对象是否存在时就有安全隐患所以需要加锁同步

//懒汉式安全方法class Single {private static Single s = null;private Single() {}public static Single getInstance() {if(s == null) {synchronized(Single.class) {//静态方法的锁没有this,使用该类所属的字节码文件对象作为锁if(s == null)s = new Single();}}return s;}}

线程通信同步安全问题

/*线程通信优化*/class Res {private String name;private String sex;privateboolean flag = false;public synchronized void set(String name, String sex) {if(flag)try{this.wait();}catch(Exception e) {}this.name = name;this.sex = sex;flag = true;this.notify();}public synchronized void out() {if(!flag)try{this.wait();}catch(Exception e) {}System.out.println(this.name + "=============" + this.sex);flag = false;this.notify();}}class Output implements Runnable {Res r;Output(Res r) {this.r = r;}public void run() {while(true) {r.out();}}}class Input implements Runnable {Res r;Input(Res r) {this.r = r;}public void run() {int x = 0;while(true) {if(x == 0) r.set("Tom", "man");elser.set("丽丽", "女女女女女女");x = (x + 1) % 2;}}}class InputOutputDemo2 {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();}}
在两个线程通信时,使用同步共享资源后通过等待和唤醒完成了线程通信

线程通信共享问题----等待唤醒机制

      wait()

      notify()

      notifyAll()

wait()与notify(),notifyAll()----并不是Tread类中的,而是其父类Object里的,且该三个方法一般用于同步代码中----并且需要标识其对应的锁

为什么该三个方法定义在Object类中呢?

因为当你在同步代码时要标识他们所操作线程所操作的锁,而这个锁不一定唯一可以是任意对象,所以放在所有类的父类Object。


多个生产者消费者同步共享安全问题---------while循环和notifyAll()

当多个线程操作共享数据时通过上边的两个线程通信if判断标识,notify唤醒线程会出现安全问题所以需改进代码

class Resource {private String name;private int count = 1;private boolean flag = false;public synchronized void set(String name) {while(flag)//if改用while循环判断try{this.wait();}catch(Exception e) {}this.name = name + "=====" + count++;System.out.println(Thread.currentThread().getName() + "-----------Producer----------" + this.name);flag = true;this.notifyAll();//唤醒等待队列的所有线程}public synchronized void out() {while(!flag)//if改用while循环判断try{this.wait();}catch(Exception e) {}System.out.println(Thread.currentThread().getName() + "------Consumer-----" + this.name);flag = false;this.notifyAll();//唤醒等待队列的所有线程}}class Producer implements Runnable {private Resource r;Producer(Resource r){this.r = r;}public void run () {while(true) {r.set("Product : Tool");}}}class Consumer implements Runnable {private Resource r;Consumer(Resource r){this.r = r;}public void run() {while(true) {r.out();}}}class ProducerConsumerDemo {public static void main(String[] args) {Resource r = new Resource();Producer producer = new Producer(r);Consumer consumer = new Consumer(r);Thread proThread1 = new Thread(producer);Thread proThread2 = new Thread(producer);Thread conThread1 = new Thread(consumer);Thread conThread2 = new Thread(consumer);proThread1.start();proThread2.start();conThread1.start();conThread2.start();}}

多个生产者消费者同步共享JDK1.5 新特性---------java.util.concurrent.locks---Lock接口----Condition接口

Lock接口替代synchronized

Condition接口替代Object的wait,notify,notifyAll-----------使用方法await,signal,signalAll

Lock接口三个实现类

       |--ReentrantLock

       |--ReentrantReadWriteLock.ReadLock

       |--ReenttrantReadWriteLock.WriteLock

用JDK1.5的Lock锁改动多个线程同步的代码

//这只是对原来代码的改用并没有用到新的特点import java.util.concurrent.locks.*;class Resource {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 {lock.lock();try {while(flag)//try{this.wait();}catch(Exception e) {}condition.await();this.name = name + "=====" + count++;System.out.println(Thread.currentThread().getName() + "-----------Producer----------" + this.name);flag = true;//this.notifyAll();condition.signalAll();} finally {//因为锁是资源最后一定要释放lock.unlock();}}public void out() throws InterruptedException{lock.lock();try {while(!flag)//try{this.wait();}catch(Exception e) {}condition.await();System.out.println(Thread.currentThread().getName() + "------Consumer-----" + this.name);flag = false;//this.notifyAll();condition.signalAll();} finally {lock.unlock();}}}class Producer implements Runnable {private Resource r;Producer(Resource r){this.r = r;}public void run () {while(true) {try {r.set("Product : Tool");} catch(InterruptedException e) {}}}}class Consumer implements Runnable {private Resource r;Consumer(Resource r){this.r = r;}public void run() {while(true) {try {r.out();} catch(InterruptedException e) {}}}}class ProducerConsumerJDKenhanceDemo {public static void main(String[] args) {Resource r = new Resource();Producer producer = new Producer(r);Consumer consumer = new Consumer(r);Thread proThread1 = new Thread(producer);Thread proThread2 = new Thread(producer);Thread conThread1 = new Thread(consumer);Thread conThread2 = new Thread(consumer);proThread1.start();proThread2.start();conThread1.start();conThread2.start();}}

await与signal 不同于wait与notify

await可以等待指定的condition

signal可以唤醒指定的condition

所以新版本的Lock实现同步代码如下

import java.util.concurrent.locks.*;class Resource {private String name;private int count = 1;private boolean flag = false;//创建锁private Lock lock = new ReentrantLock();private Condition conditionProducter = lock.newCondition();private Condition conditionConsumer = lock.newCondition();public void set(String name) throws InterruptedException {lock.lock();try {while(flag)//try{this.wait();}catch(Exception e) {}conditionProducter.await();this.name = name + "=====" + count++;System.out.println(Thread.currentThread().getName() + "-----------Producer----------" + this.name);flag = true;//this.notifyAll();conditionConsumer.signal();} finally {//因为锁是资源最后一定要释放lock.unlock();}}public void out() throws InterruptedException{lock.lock();try {while(!flag)//try{this.wait();}catch(Exception e) {}conditionConsumer.await();System.out.println(Thread.currentThread().getName() + "------Consumer-----" + this.name);flag = false;//this.notifyAll();conditionProducter.signal();} finally {lock.unlock();}}}class Producer implements Runnable {private Resource r;Producer(Resource r){this.r = r;}public void run () {while(true) {try {r.set("Product : Tool");} catch(InterruptedException e) {}}}}class Consumer implements Runnable {private Resource r;Consumer(Resource r){this.r = r;}public void run() {while(true) {try {r.out();} catch(InterruptedException e) {}}}}class ProducerConsumerJDKenhanceDemo2 {public static void main(String[] args) {Resource r = new Resource();Producer producer = new Producer(r);Consumer consumer = new Consumer(r);Thread proThread1 = new Thread(producer);Thread proThread2 = new Thread(producer);Thread conThread1 = new Thread(consumer);Thread conThread2 = new Thread(consumer);proThread1.start();proThread2.start();conThread1.start();conThread2.start();}}


停止线程


原有的stop方法已经过时,如何停止线程?

只有一种方法,run方法结束。

开启多线程运行,运行代码通常是循环结构,只要控制循环,就可以让run方法结束,也就是线程结束。

代码操作----在循环中使用boolean型标记,对外提供一个修改标记方法

特殊情况:

多线程中当线程冻结时,不会读到标记,线程就无法停止

如何解决这个问题?

interrupt对冻结状态清除,强制让线程回复到运行状态中,这样就可以修改标记,让线程结束

 

守护线程(后台线程)

setDanmon()设置成守护线程---必须在线程启动前设置

 

join方法

当A线程执行到了B线程的join方法时,A线程等待,等B线程执行完,A才会执行

Join可以临时加入线程

 

线程优先级----1---10

默认优先级5

可以通过setPriority()设置线程优先级

MAX_PRIORITY

MIN_PRIORITY

NORM_PRIORITY

 

yield(): 暂停当前正在执行的线程对象,并执行其他线程。


0 0