黑马程序员_java多线程
android培训、java培训、期待与您交流!
多线程
一、 线程的基础
JAVA中main方法开始就是一个线程,在JAVA中他就是主线程,我们之前所学的都是在进行单线程变成就是只有主线程一条线程在运行,多线程是什么,就好比你在使用360可以杀毒,可以清理垃圾,在一个程序下可以同时做多个事情。这就是多线程。
由于我们的操作系统可以同时执行很多的任务,你打开任务管理器可以看到非常多的进程在同时执行,每一个任务,就是一个进程,之前所说的360可以说一个以进程。可以这样说:操作系统可以同时执行多个任务,每个任务就是进程,进程可以同时执行多个任务,每个任务就是线程。
二、 线程的创建方式
线程的创建有2种方式:
第一种方式,继承Thread类的方式
public class FirstThread extends Thread{ FirstThread(String name) { super(name); } public void run() { for(int i=0;i<100;i++) { System.out.println(getName()+" "+i); } } public static void main(String[] args) { new FirstThread("第一条线程").start(); new FirstThread("第二条线程").start(); } }
使用继承Thread方法来创建线程,多个线程之间无法共享线程的实例变量。
第二种方式,实现runnable接口创建线程
public class SecoundThread implements Runnable { public void run() { for(int i=0;i<100;i++) { System.out.println(Thread.currentThread().getName()+" "+i); } } public static void main(String[] args) { SecoundThread st=new SecoundThread(); new Thread(st,"第一个线程").start(); new Thread(st,"第二个线程").start(); } }
三、 线程的生命周期
四、 控制线程的方法
jion方法:如果使用jion方法加入某个线程会先执行完加入的线程,才会继续执行之前的线程
后台线程:可以成为守护线程。通过setDaemo(boolean)的方法来设置,当参数为真,就是把该线程设为了守护线程,只有当所有前台线程都死亡,后台线程才会自动死亡。所有设置守护线程需要在start()方法之前调用。
线程睡眠:sleep,让当前线程等待一段时间之后再继续执行,使用方法Thread.sleep(1000)这样即是让当前线程暂停运行1秒
线程让步:yield可以暂停当前线程,让其他线程执行。
设置线程优先级:setPriority()方法用来设置优先级,JAVA中自带10个优先级(1-10)但是由于系统会有不同的区别所以最好使用JAVA自带的静态常量来设置优先级
MAX_PRIORITY 最高优先级10
MIN_PRIORITY 最低优先级1
NORM_PRIORITY 分配给线程的默认优先级
当然也可以通过自己设置数字来设置不过并不推荐
五、 线程的安全性(同步)
关于线程安全性是由于多个线程访问同一个数据由于底层线程一直处于切换的过程,可以能会出现数据的安全问题,例如:银行取钱的问题,A去银行取钱,钱已经取了,但是还没有修改余额,这时线程切换到B,B也去取了钱,也还没修改余额,然后线程回到A继续执行,余额修改好了,线程在回到B,这是因为B已经取好了钱,修改余额,这里的安全性问题就在B取钱的时候已经跳过了余额判断等取钱的条件,如果这是A取完钱余额修改完后余额已经不足B要取得钱,但是程序上B已经把钱去玩了,这时候就会安全问题。
解决办法——同步
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
在java中对于多线程的安全问题提供了专业的解决方式——synchronized(同步)
这里也有两种解决方式,一种是同步代码块,还有就是同步函数。都是利用关键字synchronized来实现。
从JAVA5开始还提供了一种更为强大的同步机制,同步锁(LOCK)
import java.util.concurrent.locks.ReentrantLock; public class LockTest implements Runnable{ //定义锁对象 private final ReentrantLock lock = new ReentrantLock(); int i=80; public void run() { //加锁 lock.lock(); try { if(i>50) { System.out.println(Thread.currentThread().getName()+i); i=i-50; } else { System.out.println(Thread.currentThread().getName()+"i已经小于0"); } } finally { //释放锁 lock.unlock(); } } public static void main(String[] args) { LockTest lt=new LockTest(); new Thread(lt,"第1个线程").start(); new Thread(lt,"第2个线程").start(); } }
死锁现象:由于给线程都加上了,当2个线程互相等待对方释放资源的时候就会发生死锁,一旦发生死锁,整个程序既不会发生任何异常,也不会有提示,但是就是所有线程都处于阻塞状态,无法继续。
class DeadLock implements Runnable { public int flag = 1; static Object o1 = new Object(), o2 = new Object(); /* * 当类的对象flag=1时(T1),先锁定O1,睡眠500毫秒,然后锁定O2; * 而T1在睡眠的时候另一个flag=0的对象(T2)线程启动,先锁定O2,睡眠500毫秒,等待T1释放O1; * T1睡眠结束后需要锁定O2才能继续执行,而此时O2已被T2锁定; T2睡眠结束后需要锁定O1才能继续执行,而此时O1已被T1锁定; * T1、T2相互等待,都需要对方锁定的资源才能继续执行,从而死锁。 */ @Override public void run() { System.out.println("flag=" + flag); if (flag == 1) { synchronized (o1) { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } synchronized (o2) { System.out.println("1"); } } } if (flag == 0) { synchronized (o2) { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } synchronized (o1) { System.out.println("0"); } } } } public static void main(String[] args) { DeadLock td1 = new DeadLock(); DeadLock td2 = new DeadLock(); td1.flag = 1; td2.flag = 0; new Thread(td1).start(); new Thread(td2).start(); } }
六、 线程的通信
线程间的相互作用:线程之间需要一些协调通信,来共同完成一件任务。
为了实现这种功能,Object类中相关的方法,wait()、notify()、notifyAll()。
对于使用synchronized修饰的同步方法,因为是该类的默认实例(this)所有可以直接调用这3个方法。
如果是synchronized修饰的同步代码块,因为同步监视器是synchronized后面括号的对象,所以必须使用对象调用者3个方法。
关于这3个方法的具体使用方法
class Res { String name, sex; boolean flag = false; } 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 (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (x == 0) { r.name = "张三"; r.sex = "男"; } else { r.name = "zhan"; r.sex = "nv"; } 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 (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(r.name + " " + r.sex); r.flag = false; r.notify(); } } } } public class ThreadTel { 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(); } }
在JAVA 1.5版本之后提供了新的线程通信方法,与同步锁一起使用,condition
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; class Res2 { String name, sex; private ReentrantLock lock; private Condition cond; boolean flag = false; } class Input2 implements Runnable { private Res2 r; private ReentrantLock lock; private Condition cond; Input2(Res2 r, ReentrantLock lock,Condition cond) { this.r = r; this.lock = lock; this.cond=cond; } public void run() { int x = 0; while (true) { lock.lock(); try { if (r.flag) cond.await(); if (x == 0) { r.name = "张三"; r.sex = "男"; } else { r.name = "zhan"; r.sex = "nv"; } x = (x + 1) % 2; r.flag = true; cond.signal(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { lock.unlock(); } } } } class Output2 implements Runnable { private Res2 r; private ReentrantLock lock; private Condition cond; Output2(Res2 r, ReentrantLock lock,Condition cond) { this.r = r; this.lock = lock; this.cond=cond; } public void run() { while (true) { lock.lock(); try { if (!r.flag) { cond.await(); } System.out.println(r.name + " " + r.sex); r.flag = false; cond.signal(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { lock.unlock(); } } } } public class ThreadTel2 { public static void main(String[] args) { Res2 r = new Res2(); ReentrantLock lock = new ReentrantLock(); Condition cond=lock.newCondition(); Input2 in = new Input2(r, lock,cond); Output2 out = new Output2(r, lock,cond); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } }
- 黑马程序员---java基础知识之多线程
- 黑马程序员_毕向东JAVA基础_多线程
- 黑马程序员——【Java基础】——多线程
- 黑马程序员_Java多线程
- 黑马程序员——Java基础--- 多线程
- 黑马程序员-JAVA基础-多线程(上)
- 黑马程序员-Java基础:多线程
- 黑马程序员——Java基础——多线程
- 黑马程序员_java基础加强7_多线程加强
- 黑马程序员:Java基础总结----多线程
- 黑马程序员_java基础-多线程
- 黑马程序员—Java多线程
- 【黑马程序员】--------java基础---包、多线程
- 黑马程序员----java面向对象05(多线程)
- 黑马程序员--Java学习日记之多线程
- 黑马程序员_Java多线程(一)
- 黑马程序员一一Java的多线程笔记
- 黑马程序员-Java中的多线程
- 黑马程序员-Java多线程-day11
- 黑马程序员--java基础--多线程