黑马程序员——Java基础——多线程
来源:互联网 发布:联合国商品数据库 编辑:程序博客网 时间:2024/06/01 09:04
多线程
概述
进程:是一个正在执行中的程序
每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者 叫一个控制单元
线程:是进程中的一个独立的控制单元,线程控制着进程的执行
一个进程中至少有一个线程
java vm(虚拟机) 启动的时候会有一个进程java.exe,该进程中至少有一个线程负责java程序的执行,且这个线程运行的代码存在于main方法中,这个线程称之为主线程
更细节说明虚拟机,jvm启动不止一个线程,还有负责垃圾回收机制的线程
多线程的意义:多线程的出现,可以让程序中的多部分代码同时执行
创建线程_继承Thread类
如何创建线程:
1. 继承Thread类;
2. 复写run();//将自定义的代码储存在run()中,方便线程调用
3. 调用线程的strat();//1. 启动线程 2. 调用run方法
多线程的特性:随机性
为什么要覆盖run():
Thread用于描述线程,该类定义了一个功能用于存储线程要运行的代码,该存储功能就是run()方法
public class Test1 { public static void main(String[] args){ Demo d1 = new Demo("one+"); d1.start(); Demo d2 = new Demo("two++"); d2.start(); }}class Demo extends Thread{ Demo(String name){ System.out.println(name); } public void run (){ for(int i = 0; i <= 60; i++ ){ System.out.println(Thread.currentThread().getName() + "::" + i); } }}
线程运行状态
被创建
运行:start()
冻结(睡眠、等待):sleep(time)、wait()、notify()
消亡:stop()、run()方法结束
临时(阻塞)状态:具备运行资格,但是没有执行权
获取线程对象以及名称
获取当前对象:static Thread currentThread()
获取线程名称:getName()
设置线程名称:setNmae()
创建线程_实现Runnable接口
- 实现Runnable接口
- 覆盖Runnable接口中的run()方法
将线程要运行的代码存放在该run()方法中 - 通过Thread类建立对象
- 将Runnable接口的子类对象作为实际参数传递给Thread类的构造参数
- 调用Thread类的start()方法开启线程并调用Runnable接口子类的run()方法
实现方式和继承方式的区别
避免了单继承的局限性,在定义线程的时候建议使用实现方式
两种方法的区别:
继承Thread类:线程运行的代码存放在Thread子类run()方法中
实现Runnable接口:线程运行的代码存放在接口的子类的run()方法中
class Ticket implements Runnable{ private int tick = 100; Object obj = new Object(); public void run() { while(true){ if(tick>0){ synchronized(obj){ try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName() + "sela:" + tick--); } } } }}public class SellTicketDemo1 { public static void main(String[] args){ Ticket t = new Ticket(); new Thread(t).start(); new Thread(t).start(); new Thread(t).start(); new Thread(t).start(); }}
多线程的安全问题:
问题原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完另一个线程参与进来执行,导致共享数据的错误
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完再执行过程中,其他线程不能参与执行
同步代码块:
synchronized(对象){ 需要被同步的代码}
参数“对象”就如同锁,持有锁的线程可以在同步中执行
没有持有锁的线程,即使获取了CPU的执行权,也不能执行
同步的前提:
1. 必须要有两个以上的线程
2. 必须是多个线程使用同一个锁
必须保证在同步中有一个线程在运行
好处:解决了多线程的安全问题
弊端:每次都要判断锁,消耗资源
同步函数:
如何找到函数中的多线程同步问题:
1. 明确哪些代码是多线程运行代码
2. 明确共享数据
3. 明确多线程运行代码中哪些语句是操作共享数据的
同步代码块:
Object obj = new Object();public void test(){ synchronized(obj){ System.out.println("xxxx"); }}
同步函数:(用synchronized来修饰函数即可)
public synchronized void test(){ System.out.println("xxxx");}
同步函数用的是哪一个锁:
函数需要被对象调用。那么函数都有一个所属对象引用
就是this,所以同步函数使用的锁是this
同步函数被静态修饰后,使用的锁是什么:
被静态修饰后,不在是this。静态进内存时,内存中没有本类对象,
但是一个顶有该类对应的字节码文件对象。类名.class 该对象的类型是class
静态的同步方法,使用的锁是该方法所在类的字节码文件对象 类名.class
多线程_单例设计模式-懒汉式
饿汉式
class Single{ private static final Single s = new Single(); private Single(){} //Instance实例 public static Single getInstance(){ return s; }}
懒汉式(延迟加载单例设计模式示例)
class Single{ private static Single s = null; private Single(){} /* 同步方法后效率会比较低效 public static synchronized Single getInstance(){ if(s == null){ return s; } } */ public static Single getInstance(){ if(s == null){ synchronized(Single.class){ if(s == null) s = new Single(); } } }}
懒汉式和饿汉式有什么不同:
1. 懒汉式的特点在于延时加载
2. 懒汉式延时加载在多线程的时候会出现线程安全问题
3. 用同步代码块和同步方法都行,但是会稍微低效,用双重判断可解决效率问题
4. 加同步的时候使用的锁为该类所属的字节码对象
多线程_死锁
同步中嵌套同步,而锁却不同
死锁示例:
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(); }}class Test implements Runnable{ private boolean flag; Test(boolean flag){ this.flag = flag; } public void run() { if(flag){ synchronized(MyLock.locka){ System.out.println("if locka"); synchronized(MyLock.lockb){ System.out.println("if lockb"); } } }else{ synchronized(MyLock.lockb){ System.out.println("else lockb"); synchronized(MyLock.locka){ System.out.println("else lockb"); } } } }}class MyLock{ static Object locka = new Object(); static Object lockb = new Object();}
多线程间的通信
多个线程在操作同一个资源,但是操作的动作不同
等待唤醒机制:
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{ String name; String sex; boolean flag = false;}/** wait();* notify(); * notifyall();* 都是用在同步中,因为要对持有监视器(锁)的线程操作* 所以要使用在同步中,因为只有同步才具有锁*/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) try{r.wait();}catch(Exception e){} if(x == 0){ r.name = "mike"; r.sex = "man"; }else{ r.name = "lili"; r.sex = "woman"; } 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) try{r.wait();}catch(Exception e){} 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(); new Thread(new Input(r)).start(); new Thread(new Output(r)).start(); }}class Res{ private String name; private String sex; private boolean 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; notify(); } public synchronized void out(){ if(!flag) try{this.wait();}catch(Exception e){} System.out.println(name + "..." + sex); flag = false; 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("milk", "man"); }else{ r.set("lili", "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 ProducerConsumer { public static void main(String[] args){ Resource r = new Resource(); new Thread(new Producer(r)).start(); new Thread(new Consumer(r)).start(); }}class Resource{ private String name; private int count = 1; private boolean flag = false; public synchronized void set(String name){ while(flag) try{wait();}catch(Exception e){} this.name = name + ".." + count++; System.out.println(Thread.currentThread().getName() + "...生产者..." + this.name); flag = true; this.notifyAll(); } public synchronized void out(){ while(!flag) try{wait();}catch(Exception e){} System.out.println(Thread.currentThread().getName() + "...消费者..." + this.name); flag = false; this.notifyAll(); }}class Producer implements Runnable{ private Resource res; Producer(Resource res){ this.res = res; } public void run() { while(true){ res.set("++商品++"); } }}class Consumer implements Runnable{ private Resource res; Consumer(Resource res){ this.res = res; } public void run() { while(true){ res.out(); } }}
生产者消费者JDK1.5升级新特性版本(显式的锁机制):
将同步synchronized替换成现实Lock操作
将Object中的wait,notify,notifyAll,替换Condition对象
该对象可以通过Lock锁进行获取
public class ProducerConsumer { public static void main(String[] args){ Resource r = new Resource(); new Thread(new Producer(r)).start(); new Thread(new Consumer(r)).start(); new Thread(new Consumer(r)).start(); new Thread(new Consumer(r)).start(); }}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 (InterruptedException e) { e.printStackTrace(); } } }}class Consumer implements Runnable{ private Resource res; Consumer(Resource res){ this.res = res; } public void run() { while(true){ try { res.out(); } catch (InterruptedException e) { e.printStackTrace(); } } }}
多线程_停止线程
stop()已经过时,只有一种run()方法结束
开启多线程,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,结束线程
Thread类中提供interrupt()方法,强制让给线程恢复到运行状态中来
public class StopThreadDemo { 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 = 0; while(true){ if(num++ == 60){ t1.interrupt(); t2.interrupt(); break; } System.out.println(Thread.currentThread().getName() + "......" + num); } }}class StopThread implements Runnable{ private boolean flag = true; public synchronized void run(){ while(flag){ try{ wait(); }catch(InterruptedException e){ System.out.println(Thread.currentThread().getName() + "...Exception"); flag = false; } System.out.println(Thread.currentThread().getName() + "...run"); } } public void changeFlag(){ flag = false; }}
多线程_守护线程
- 在线程启动前调用
- 当前台线程全部运行结束后,后台线程自动结束运行(Java虚拟机退出)
setDeamon():
Thread t = new Thread(对象);t.setDeamon();t.start();
多线程_Join()方法
当A线程执行到了B线程的.join(),A线程就会等待,等B线程都执行完,A才会执行多线程_优先级 & yield()方法
setPriority(int newPriority);优先级一共10级,10级别最优先
MAX_PRIORITY 10级
MIN_PRIORITY 1级别
NORM_PRIORITY 5级别
Thread.yield();临时释放线程执行权,能达到所有线程平均运行效果
几种多线程的定义方式
public class TestThread { public static void main(String[] args){ new Thread(){ public void run(){ for(int i=0; i<100; i++){ System.out.println(Thread.currentThread().getName() + "...." + i); } } }.start(); Runnable r = new Runnable(){ public void run(){ for(int i=0; i<100; i++){ System.out.println(Thread.currentThread().getName() + "...." + i); } } }; new Thread(r).start(); for(int i=0; i<100; i++){ System.out.println(Thread.currentThread().getName() + "...." + i); } }}
- 黑马程序员——Java基础---多线程
- 黑马程序员——Java基础---多线程
- 黑马程序员——Java基础---多线程
- 黑马程序员——Java基础---多线程
- 黑马程序员——Java基础---多线程
- 黑马程序员——java基础---多线程
- 黑马程序员——Java基础多线程
- 黑马程序员——Java基础->多线程
- 黑马程序员——Java基础---多线程
- 黑马程序员——java基础---多线程
- 黑马程序员——Java基础---多线程
- 黑马程序员——java基础--多线程
- 黑马程序员——java基础--多线程
- 黑马程序员——Java基础--- 多线程
- 黑马程序员——Java基础---多线程
- 黑马程序员——Java基础---多线程
- 黑马程序员——java基础-多线程
- 黑马程序员——Java基础:多线程
- Datazen配置
- iOS开发UI高级—09控制器的View的创建
- 剑指oofer 62 - 序列化二叉树
- 什么是云数据库
- 关于unterminated argument list invoking macro \”%s\”"
- 黑马程序员——Java基础——多线程
- Eclipse的快捷键
- 什么是云服务器私有网络和防火墙
- leetcode[83]:Remove Duplicates from Sorted List
- 【整理】常见的数组排序方法以及代码实现
- 7 Steps for Learning Data Mining and Data Science
- 线性表节点
- iOS开发UI高级—10使用picker View控件完成一个简单的选餐应用
- 【SDUT 3253】 Game!