概述
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
本人习惯将总结写在代码里~
线程间通信问题:
package cn.fuxi.duoxiancheng2;
/**
* 线程间通信
* 多线程在处理统一资源,但是任务却不同,这时候就需要线程间通信.
* 等待/唤醒机制涉及的方法:
* 1.wait():让线程处于冻结状态,被wait的线程会被存储到线程池中.
* 2.notify():唤醒线程池中的一个线程(任何一个都有可能).
* 3.notifyAll():唤醒线程池中的所有线程.
*
* P.S.
* 1.这些方法都必须要定义在同步中,因为这些方法是用于操作线程状态的方法.
* 2.必须要明确到底操作的是哪个锁上的线程!
* 3.wait和sleep的区别?
* 1--wait可以指定时间也可以不指定.sleep必须指定时间.
* 2--在同步中时,对cpu的执行权和锁的处理不同.
* wait:释放执行权,释放锁.
* sleep:释放执行权,不释放锁.
*
* 为什么线程操作的方法waitnotifynotifyAll定义在了Object类中?
* 因为这些方法是监视器的方法,监视器其实就是锁.
* 锁可以是任意的对象,任意的对象调用的方式一定在Object类中.
*/
//生产者-消费者问题:
class Resource{
private String name;
private String sex;
private boolean flag = false;
public synchronized void set(String name,String sex){
if(flag)
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.name = name;
this.sex = sex;
flag = true;
this.notify();
}
public synchronized void out(){
if(!flag)
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+"..."+sex);
flag = false;
this.notify();
}
}
class Input implements Runnable{
Resource r;
Input(Resource r){
this.r = r;
}
public void run(){
int x = 0;
while (true){
if(x==0){
r.set("mike","男");
}else{
r.set("lili", "女");
}
x = (x+1)%2;
}
}
}
//输出
class Output implements Runnable{
Resource r;
Output(Resource r){
this.r = r;
}
public void run(){
while(true){
r.out();
}
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
//创建资源
Resource r = new Resource();
//创建任务
Input in = new Input(r);
Output out = new Output(r);
//创建线程,执行路径
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
//开启线程
t1.start();
t2.start();
}
}
运行结果:
lili...女
mike...男
lili...女
mike...男
lili...女
mike...男
lili...女
mike...男
lili...女
mike...男
lili...女
mike...男
lili...女
mike...男
lili...女
生产者消费者问题:
package cn.fuxi.duoxiancheng2;
/**
* 多生产者-多消费者问题
*/
class Resource2{
private String name;
private int count =1;
private boolean flag = false;
public synchronized void set(String name){
if(flag)
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.name = name+count;
count++;
System.out.println(Thread.currentThread().getName() + "...生产者..."+ this.name);
flag = true;
notify();
}
public synchronized void out(){
if(!flag)
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = false;
notify();
System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
}
}
class Producer implements Runnable{
private Resource2 r;
Producer(Resource2 r){
this.r = r;
}
public void run(){
while(true){
r.set("烤全羊");
}
}
}
class Consumer implements Runnable{
private Resource2 r;
Consumer(Resource2 r){
this.r = r;
}
public void run(){
while(true){
r.out();
}
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
Resource2 r = new Resource2();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread tp1 = new Thread(pro);
Thread tp2 = new Thread(pro);
Thread tc3 = new Thread(con);
Thread tc4 = new Thread(con);
tp1.start();
tp2.start();
tc3.start();
tc4.start();//出现多消费者消费同一只烤全羊
}
}
/*
*原因分析:
*1.线程Thread-1获取的cpu执行权及锁,生产了烤全羊123,将flag设置为true.然后,Thread-1又
*重新获取到cpu执行权,由于flag为true,故执行wait方法,阻塞.Thread-2接着获取到CPU执行权,
*由于flag为true,故执行wait方法,也阻塞.
*2.线程Thread-4获取到CPU执行权及锁,消费了烤全羊123,将flag设置为false.然后线程Thread-1
*被唤醒,但是并没有获取到锁,而是线程Thread-4接着获取到CPU执行权及锁,然而此时flag为false,所以
*Thread-4阻塞,之后Thread-3接着获取到CPU执行权及锁,然而flag为false,所以Thread-3也阻塞.
*3.线程Thread-1获取到CPU执行权及锁,不需要if判断,直接生产124,然后又唤醒线程Thread-2获取到
*执行权及锁,不需要if判断,直接生产125,从而造成烤全羊124还没有消费,就生产了125的情况.
*/
运行结果:
Thread-2...消费者...烤全羊21949
Thread-1...生产者...烤全羊21950
Thread-0...生产者...烤全羊21951
Thread-3...消费者...烤全羊21951
Thread-2...消费者...烤全羊21951
Thread-1...生产者...烤全羊21952
Thread-0...生产者...烤全羊21953
Thread-3...消费者...烤全羊21953
Thread-2...消费者...烤全羊21953
Thread-1...生产者...烤全羊21954
Thread-0...生产者...烤全羊21955
Thread-3...消费者...烤全羊21955
Thread-2...消费者...烤全羊21955
改进:
package cn.fuxi.duoxiancheng2;
/**
* 由于if判断标记,只有一次,会导致不该运行的线程运行了,出现了数据错误的情况.故修改成while判断标记,
* 线程获取CPU执行权及锁后,将重新判断是否具备运行条件.
* notify只能唤醒一个线程,如果本方唤醒了本方,没有意义.而且while判断标记+notify会导致死锁.notifyAll
* 解决了本方线程一定会唤醒对方线程的问题.
*
* P.S.
* while判断标记+notify会导致死锁的示例:
* 如果将上面的代码中的if判断标记修改成wile判断标记,就会出现死锁的现象,前2步与原来是一致的.
* 第三步如下:
* 3.线程Thread-1获取到CPU执行权及锁,通过while语句判断,直接生产烤全羊124,将flag设置为true.
* 然后又唤醒线程Thread-2获取到CPU执行权及锁,没有通过while语句判断,阻塞.线程Thread-1又获取到
* CPU执行权及锁,通不过while语句判断,也阻塞,此时Thread-1,2,3,4都阻塞,故死锁.
*/
class Resource3{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name){
while(flag)
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.name = name + count;
count++;
System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
flag = true;
notifyAll();
}
public synchronized void out(){
while(!flag)
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
flag = false;
notifyAll();
}
}
class Producer3 implements Runnable{
private Resource3 r;
Producer3(Resource3 r){
this.r = r;
}
public void run(){
while(true){
r.set("烤鸭");
}
}
}
class Consumer3 implements Runnable{
private Resource3 r;
Consumer3(Resource3 r){
this.r = r;
}
public void run(){
while(true){
r.out();
}
}
}
public class ThreadDemo3 {
public static void main(String[] args) {
Resource3 r = new Resource3();
Producer3 pro = new Producer3(r);
Consumer3 con = new Consumer3(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
运行结果:
Thread-2...消费者...烤鸭54351
Thread-0...生产者...烤鸭54352
Thread-3...消费者...烤鸭54352
Thread-1...生产者...烤鸭54353
Thread-2...消费者...烤鸭54353
Thread-0...生产者...烤鸭54354
Thread-3...消费者...烤鸭54354
Thread-1...生产者...烤鸭54355
Thread-2...消费者...烤鸭54355
Thread-0...生产者...烤鸭54356
Thread-3...消费者...烤鸭54356
Thread-1...生产者...烤鸭54357
Thread-2...消费者...烤鸭54357
Thread-0...生产者...烤鸭54358
JDK1.5新特性:
package cn.fuxi.duoxiancheng2;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* JDK1.5新特性
* 同步代码块,就是对于锁的操作是隐式的.
* JDK1.5以后将同步和锁封装成了对象,并将操作锁的隐式方式定义到了该对象中,将隐式动作变成了显示动作.
* Lock接口:出现替代了同步代码块或者同步函数,将同步的隐式操作变成显示锁操作,同时更为灵活,可以一个锁
* 加上多组监视器.
* lock():获取锁.
* unlock():释放锁,未来防止出现异常,导致锁无法被关闭,所以锁的关闭动作要放在finally中.
* Condition接口:出现替代了Object中的wait,notify,notifyAll方法,将这些监视器方法单独经行了
* 封装,变成Condition监视器对象,可以任意锁进行组合.
* Condition接口中的await方法对应于Object中的wait方法.
* Condition接口中的signal方法对应于Object中的notify方法.
* Condition接口中的signalAll方法对应于Object中的notifyAll方法.
*
* 使用一个Lock,一个Condition修改多生产者,多消费者的问题.
*/
class Resource6{
private String name;
private int count = 1;
private boolean flag = false;
//创建一个锁对象
Lock lock = new ReentrantLock();
//通过已有的锁获取该锁上的监视器对象
Condition con = lock.newCondition();
public void set(String name){
lock.lock();
try{
while(flag)
try {
con.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.name = name +count;
count++;
System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
flag = true;
con.signalAll();
}finally{
lock.unlock();
}
}
public void out(){
lock.lock();
try{
while(!flag)
try {
con.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = false;
con.signalAll();
System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
}finally{
lock.unlock();
}
}
}
class Producer6 implements Runnable{
private Resource6 r ;
Producer6(Resource6 r){
this.r = r;
}
public void run(){
while(true){
r.set("烤鸭");
}
}
}
class Consumer6 implements Runnable{
private Resource6 r;
Consumer6(Resource6 r){
this.r = r;
}
public void run(){
while(true){
r.out();
}
}
}
public class ThreadDemoJDK5 {
public static void main(String[] args) {
Resource6 r = new Resource6();
Producer6 pro = new Producer6(r);
Consumer6 con = new Consumer6(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
运行结果:
Thread-1...生产者...烤鸭17875
Thread-3...消费者...烤鸭17875
Thread-1...生产者...烤鸭17876
Thread-3...消费者...烤鸭17876
Thread-1...生产者...烤鸭17877
Thread-3...消费者...烤鸭17877
Thread-1...生产者...烤鸭17878
Thread-3...消费者...烤鸭17878
Thread-1...生产者...烤鸭17879
Thread-3...消费者...烤鸭17879
多线程的方法:
package cn.fuxi.duoxiancheng3;
/**
* 停止线程
* 怎么控制线程的任务结束呢?
* 任务中都会有循环结构,只要控制住循环就可以结束任务.
* 控制循环通常就是用定义标记来完成.
*/
class StopThread implements Runnable{
private boolean flag = true;
public void run(){
while(flag){
System.out.println(Thread.currentThread().getName()+"...");
}
}
public void setFlag(){
flag = false;
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
StopThread st = new StopThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int num = 1;
for(;;){
if(++num==50){
st.setFlag();
break;
}
System.out.println("main..."+num);
}
}
}
运行结果:
Thread-1...
Thread-0...
Thread-1...
main...47
Thread-1...
Thread-0...
Thread-1...
main...48
Thread-1...
Thread-0...
Thread-1...
main...49
Thread-1...
Thread-0...
package cn.fuxi.duoxiancheng3;
/**
* 如果线程处于了冻结状态,无法读取标记,如何结束呢?
* 可以使用interruput()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备CPU的执行资格.
* 强制动作会发生InterruptedException,一定要记得处理.
*/
class StopThread2 implements Runnable{
private boolean flag = true;
public synchronized void run(){
while(flag){
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"..."+e);
flag = false;
}
System.out.println(Thread.currentThread().getName()+"..............");
}
}
public void setFlag(){
flag = false;
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
StopThread2 s2 = new StopThread2();
Thread t1 = new Thread(s2);
Thread t2 = new Thread(s2);
t1.start();
t2.start();
int num = 1;
for(;;){
if(++num == 50){
t1.interrupt();
t2.interrupt();
break;
}
System.out.println("main..."+num);
}
System.out.println("over");
}
}
运行结果:
main...43
main...44
main...45
main...46
main...47
main...48
main...49
over
Thread-1...java.lang.InterruptedException
Thread-1..............
Thread-0...java.lang.InterruptedException
Thread-0..............
package cn.fuxi.duoxiancheng3;
/**
* setPriority方法:更改线程的优先级
* toString方法:返回该现场的字符串表示形式,包括线程名称,优先级和线程组.
* yield方法:暂停当前正在执行的线程对象,并执行其他进程.
*
*/
class Demo2 implements Runnable{
public void run(){
for(int x = 0 ; x < 50; x++){
System.out.println(Thread.currentThread().toString()+"..."+x);
Thread.yield();//释放执行权
}
}
}
public class ThreadFangFa {
public static void main(String[] args) {
Demo2 d = new Demo2();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t2.start();
t2.setPriority(Thread.MAX_PRIORITY);
for(int x = 0;x<50;x++){
System.out.println(Thread.currentThread().toString()+"..."+x);
}
}
}
运行结果:
Thread[main,5,main]...42
Thread[Thread-1,10,main]...42
Thread[main,5,main]...43
Thread[Thread-1,10,main]...43
Thread[main,5,main]...44
Thread[Thread-1,10,main]...44
Thread[main,5,main]...45
Thread[Thread-1,10,main]...45
Thread[main,5,main]...46
Thread[Thread-1,10,main]...46
Thread[main,5,main]...47
Thread[Thread-1,10,main]...47
Thread[main,5,main]...48
Thread[Thread-1,10,main]...48
Thread[main,5,main]...49
Thread[Thread-1,10,main]...49
package cn.fuxi.duoxiancheng3;
/**
* thread.join()方法:
* 作用:让该线程先走,结束后再执行其他线程,方便调用该线程完全结束后的结果
*/
class Demo implements Runnable{
public void run(){
for(int x = 0; x< 50; x++){
System.out.println(Thread.currentThread().getName()+"..."+x);
}
}
}
public class JoinDemo {
public static void main(String[] args) {
Demo d =new Demo();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
try {
t1.join();//t1线程要申请加入进来,运行,然后主线程t1执行完毕
//临时加入一个线程运算时可用使用join方法.
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
for(int x = 0 ;x< 50 ; x++){
System.out.println(Thread.currentThread().toString()+"..."+x);
}
}
}
运行结果:
Thread-0...36
Thread-0...37
Thread-0...38
Thread-0...39
Thread-0...40
Thread-0...41
Thread-0...42
Thread-0...43
Thread-0...44
Thread-0...45
Thread-0...46
Thread-0...47
Thread-0...48
Thread-0...49
Thread[main,5,main]...0
Thread-1...0
Thread[main,5,main]...1
Thread-1...1
Thread[main,5,main]...2
Thread-1...2
Thread[main,5,main]...3
Thread-1...3
package cn.fuxi.duoxiancheng3;
/**
* 线程类其他方法
* setDaemon();
* 将该线程标记为守护线程或用户线程.当正在运行的线程都是守护线程时,Java虚拟机退出.
* 该方法必须在启动线程前调用.
*/
class StopThread3 implements Runnable{
private boolean flag = true;
public synchronized void run(){
while(flag){
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+e);
flag = false;
}
System.out.println(Thread.currentThread().getName()+"...");
}
}
public void setFlag(){
flag = false;
}
}
public class SetDaemonDemo1 {
public static void main(String[] args) {
StopThread3 s3 = new StopThread3();
Thread t1 = new Thread();
Thread t2 = new Thread();
t1.start();
t2.setDaemon(true);
t2.start();
int num = 1;
for(;;){
if(++num ==50){
t1.interrupt();
break;
}
System.out.println("main"+num);
}
System.out.println("over");
}
}
运行结果:
main38
main39
main40
main41
main42
main43
main44
main45
main46
main47
main48
main49
over
最后
以上就是美丽马里奥为你收集整理的黑马程序员——Java继承——多线程(二)的全部内容,希望文章能够帮你解决黑马程序员——Java继承——多线程(二)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复