黑马程序员--java基础--多线程
来源:互联网 发布:淘宝店如何关闭 编辑:程序博客网 时间:2024/05/21 09:35
目录:1、创建线程继承Thread类,2、创建线程run和start特点3、线程运行状态
4 、线程的第二种穿件方式实现Runnable接口5、多线程的安全问题6、多线程同步代码块7、多线程单列设计模式(懒汉式)8、多线程-死锁 9、线程间通信 10多线程lock 11、守护线程12、 多线程:13、Join方法
1创建线程 继承Thread类
建线程的第一种方式:继承Thread类.
步骤如下:
1 继承Thread类
2 覆写Thread类中的run方法
3 调用线程的start方法,这个方法有两个作用:
1.启动线程2.调用run方法
class Demo extends Thread{ public void run() { for(int x= 0;x<60;x++) System.out.println("Demo run"+x); }}class ThreadDemo1{ public static void main(String[] args) { Demo d = new Demo();//定义了一个对象,其实就是创建好了一个线程 d.start();//开启线程并执行该线程的run方法。 d.run(); for(int x= 0;x<60;x++) System.out.println("hello world"+x); }}
2创建线程run和start特点
d.start():开启线程并执行该线程的run方法。
d.run(): 仅仅是对象调用方法。而线程创建了,并没有运行。
为什么要覆盖run方法?
目的:将自定义代码存储在run方法中,让线程运行。
Thread类用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法
也就是说Thread中的run方法,用于存储线程要运行的代码
3线程运行状态
1被创建
2 运行
3 冻结状态(放弃了执行资格)
3 临时状态(阻塞状态,可以说是具备运行资格,但是没有执行权)
5 消亡
线程从被创建到运行,是通过start()方法!
线程运行到冻结,是通过sleep(time毫秒)方法结结束,是因为时间到了!冻结中还有休眠wait休眠状态对应的是被唤醒(notify)
4 线程的第二种穿件方式实现Runnable接口
步骤
1 定义类实现Runnable接口
2 覆盖Runnble接口中的run方法,将要实现的代码放在run方法当中
3 通过Thread类建立线程对象
4 将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
为什么要将Runnable接口的子类对象传递给Thread的构造函数
因为,自定义的run方法所属的对象是Runnable接口的子类对象
所以要让线程去指定 指定对象的run方法,就必须明确该run方法所属对象。
5 调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
创建多线程继承方式和实现方式的区别
实现方式:好处在于避免了但集成的局限性。
在定义线程时,建议使用实现方式implements
继承Thread:线程代码存放Thread子类run方法中
实现Runnable:线程代码存在接口的子类run方法
class Ticket implements Runnable{ private int tick= 100; public void run() { while(true) { if(tick>0) { System.out.println(Thread.currentThread().getName()+tick--); } } }}class TicketDemo { public static void main(String[] args) { Ticket t= new Ticket(); Thread t1 = new Thread(t); t1.start(); Thread t2 = new Thread(t); t2.start(); Thread t3 = new Thread(t); t3.start(); Thread t4 = new Thread(t); t4.start(); }}
5多线程的安全问题
问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完
另一个线程就参与进来执行,导致共享数据的错误。
解决办法:
对多条线程操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行
Java对于多线程的安全问题提供了专业的解决方式:同步代码块
class Ticket2 implements Runnable{ private int tick = 100; Object obj = new Object(); public void run() { while(true) { synchronized(obj)//加上的正确代码.. { if(tick>0) { //让程序稍等10毫秒 try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+tick--); } } } }}class TicketDemo2 { public static void main(String[] args) { Ticket2 tick1 = new Ticket2(); Thread t1 = new Thread(tick1); t1.start(); Thread t2 = new Thread(tick1); t2.start(); Thread t3 = new Thread(tick1); t3.start(); Thread t4 = new Thread(tick1); t4.start(); }}
6 多线程同步代码块
synchronized(对象)
{
需要被同步的代码
}
假如把对象看成锁,持有锁的线程才可以在同步中执行。
没有持有锁的线程,即使获取cpu的执行权,也进不去,因为没有获取锁
多线程同步的前提:
1 必须要有两个或者两个以上的线程。
2 必须是多个线程使用同一个锁
必须保证同步中只能有一个线程在运行
好处:解决了多线程的安全问题。
弊端:多个线程都需要判断锁,较为消耗资源
7多线程单列设计模式(懒汉式)
class Single{ private static Single s = null; private Single(){} public static Single getInstance() { if(s==null) synchronized(Single.class)//双重判断 { if(s==null) s = new Single(); } return s; }}class SingleDemo {}
8多线程-死锁
同步中还有同步导致程序停止
class Test implements Runnable{ private boolean flag; Test(boolean flag) { this.flag = flag; } public void run() { if(flag) { while(true) { synchronized(Lock.locka) { System.out.println("if locka"); synchronized(Lock.lockb) { System.out.println("if lockb"); } } } } else { while(true) { synchronized(Lock.lockb) { System.out.println("if lockb"); synchronized(Lock.locka) { System.out.println("if locka"); } } } } }}class Lock //创建一锁{ static Lock locka = new Lock(); static Lock lockb = new Lock();}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线程间通信
其实就是多个线程在操作同一个资源,操作的动作不同
思考:
1 wait(),notify(),notify()All用来操作线程,为什么定义在了Object类中
1 这些方法存在于同步汇中
2 使用这些方法时,必须要标识所属的同步锁
3 锁可以是任意对象,所以任意对象调用的方法一定定义在Object类中
2 wait()和sleep()有什么区别?
wait()释放资源,释放锁
sleep() 释放资源,不释放锁
线程间通信-等待唤醒机制
总结:wait();notify();notifyAll();都要使用在同步中,因为要对持有监视器(锁)的线程操作
所以要使用在同步中,因为只有同步才有锁的概念.
为什么这些操作线程的操作要定义在Object类中呢?
因为这些方法在操作同步中线程时,都必须要标识它们所操作线程只有的锁,
只有同一个锁上的被等待线程可以被同一个锁上的notify唤醒;
不可以对不同锁中的线程进行唤醒.
也就是说,等待和唤醒必须是同一把锁。
而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中。
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() { boolean b = true; while(true) { synchronized(r) { if(r.flag) try{r.wait();}catch(Exception e){} if(b) { r.name = "mike"; r.sex = "man"; b = false; } else { r.name = "丽丽"; r.sex = "女 女 女 女"; b = true; } 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) try{r.wait();}catch(Exception e){} System.out.println(r.name+"............"+r.sex); r.flag = false; r.notify(); } } }}class InputOutputDemo { public static void main(String[] args) { Res r = new Res(); Input in = new Input(r); Output ou = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(ou); t1.start(); t2.start(); }}
10多线程lock
提供了多线程的升级解决方案,将synchronized替换成了显示的Lock操作
将Object中的 wait,notify,notifyAll替换成了Condition对象await,signal,signalAll
该对象可以通过Lock锁进行获取
在该示例中,实现了本方只唤醒对方的操作
class Resource{ 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 { lock.lock(); try{ while(flag) condition_pro.await(); this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name); flag = true; condition_con.signal(); } finally { lock.unlock(); } } public void out()throws InterruptedException { lock.lock(); try{ while(!flag) condition_con.await(); System.out.println(Thread.currentThread().getName()+"...消费者"+this.name); flag = false; condition_pro.signal();//释放对方的锁 } finally { lock.unlock();//释放锁的动作一定要执行 } }}//生产者class Producer implements Runnable{ private Resource res; Producer(Resource res) { this.res = res; } public void run() { while(true) { try { res.set("商品"); } catch (Exception e) { } } }}//消费者class Consumer implements Runnable{ private Resource res; Consumer(Resource res) { this.res = res; } public void run() { while(true) { try { res.out(); } catch(InterruptedException e) { } } }}//主函数class ProducerConsumerDemo2 { public static void main(String[] args) { Resource re = new Resource(); Producer pro = new Producer(re); Consumer cou = new Consumer(re); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(cou); Thread t4 = new Thread(cou); t1.start(); t2.start(); t3.start(); t4.start(); }}
11守护线程
将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
该方法必须在启动线程前调用。
通俗点说:就是前台进程全部结束完之后,守护线程自动就退出了。
//需求:停止线程class StopThread implements Runnable{ private boolean flag = true; //public synchronized void run() public synchronized void run() { while(flag) { try { wait(); } catch(InterruptedException e ) { System.out.println(Thread.currentThread().getName()+"呀呀呀呀呀0.0"); //如果都已经捕获到异常,就更改flag //this.flag =false; } System.out.println(Thread.currentThread().getName()+"....run"); } this.flag = false; }}class SetDaemonDemo { public static void main(String[] args) { StopThread st = new StopThread(); Thread t1 = new Thread(st); Thread t2 = new Thread(st); //setDaemon必须要在现在标记出来。 t1.setDaemon(true); t2.setDaemon(true); t1.start(); t2.start(); int num = 0 ; while(true) { if(num++ ==60) { //结束进程 //t1.interrupt(); //t2.interrupt(); break; } System.out.println(Thread.currentThread().getName()+"...."+num); } System.out.println("over"); }}
12 多线程:Join方法
当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完A才会执行。
join可以用来临时加入线程执行
class Demo implements Runnable{ public void run() { for(int x = 0; x<70; x++) { System.out.println(Thread.currentThread().getName()+"...."+x); } }}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 x = 0;x<60;x++) { System.out.println("main...."+x); } System.out.println("over"); }}
- 黑马程序员 Java基础 --->多线程
- 黑马程序员--java基础多线程
- 黑马程序员JAVA基础-多线程
- 黑马程序员---java基础多线程
- 黑马程序员--java基础--多线程
- 黑马程序员--Java基础--多线程
- 黑马程序员-----java基础 多线程
- 黑马程序员-->Java基础-->多线程
- 黑马程序员-------java基础------多线程
- 黑马程序员--JAVA基础---多线程
- 黑马程序员--Java基础--多线程
- 黑马程序员---Java基础---多线程
- 黑马程序员---java基础--多线程
- 黑马程序员-Java基础-多线程
- 黑马程序员-----------JAVA基础----多线程
- 黑马程序员<java基础<多线程>>
- 黑马程序员-【java基础】-多线程
- 黑马程序员--java基础--多线程
- HDU 2063 过山车(最大二分匹配)
- Linux Shell编程入门
- itunes无法识别iphone的解决方法
- VLINK 的更新版本
- 婚姻中媒人存在的客观逻辑——leo鉴书45
- 黑马程序员--java基础--多线程
- 【C++基础】公有,私有和受保护的继承
- SPOJ PALIN
- 内核:offsetof + container_of 分析
- HDU2602 Bone Collector
- 旋转字符串
- Ogre练习
- HDU2709 Sumsets
- 博客的QR码