📄 java12.txt
字号:
接Java11的内容:多线程:-----------------------------------------------------------------------------------------package com.tarena.day12.thread;public class TestRunnable implements Runnable{ //写run(),调start() public static void main(String[] args) { TestRunnable tr = new TestRunnable(); Thread t = new Thread(tr); t.start(); //是线程方法,会通知调度,启动线程 //t.run();是进程方法,没有启动线程调度器,如果是run就不能实现并行效果 for (int i = 0; i < 30; i++) { System.out.println("main:"+i); try { Thread.sleep(1); } catch (Exception e) { e.printStackTrace(); } } } public void run() { for (int i = 0; i < 30; i++) { System.out.println("run:"+i); try { Thread.sleep(1); } catch (Exception e) { e.printStackTrace(); } } }}输出结果(不定):main:0run:0main:1run:1main:2run:2main:3run:3..........-----------------------------------------------------------------------------------------1.extends Thread继承Thread的好处是编码简单明了,但没有保留类继承2.implements Runnable继承接口,编码稍复杂,保留了类继承禁止使用Thread中的过时方法,因为存在着致命的隐患1.继承Thread或者Runnable,重写run()2.调用Thread.start()方法启动线程调度Daemon 守护/后台线程依赖于其他的非守护线程(生命周期),一旦非守护线程全部over,所有守护线程也都overJVM中的gc(Garbage Collection)垃圾回收就是一个守护线程System.gc可以建议JVM运行垃圾回收器-----------------------------------------------------------------------------------------package com.tarena.day12.thread;public class TestDaemon extends Thread{ public void run(){ while(true){ System.out.println("daemon"); try { Thread.sleep(1); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { TestDaemon td = new TestDaemon(); td.setDaemon(true); td.start(); //td.start(); 同一线程不能start两次 }}-----------------------------------------------------------------------------------------join:-----------------------------------------------------------------------------------------package com.tarena.day12.thread;public class TestJoin extends Thread{ public void run(){ for (int i = 0; i < 30; i++) { System.out.println(getName()+":"+i); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) throws InterruptedException { TestJoin tj1 = new TestJoin(); TestJoin tj2 = new TestJoin(); tj1.start(); tj2.start(); tj1.join(); //这里必须等tj1执行完才能执行下面的代码 for (int i = 0; i < 30; i++) { System.out.println("main:"+i); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }}-----------------------------------------------------------------------------------------sleep()/yield()的区别:sleep()有参数,调用时本线程一定会停止,无论优先级高地都会让yield()无参,本线程会参与运行权的争夺,不让位优先级低于自己的线程,只让位给优先级等于或高于自己的-----------------------------------------------------------------------------------------package com.tarena.day12.thread;public class TestSleep extends Thread{ public void run(){ for (int i = 0; i < 10; i++) { System.out.println(getName()+":"+1); try{ Thread.sleep(100); //sleep()与优先级无关 //Thread.yield(); //依赖于优先级 }catch(Exception e){ e.printStackTrace(); } } } public static void main(String[] args) { TestSleep ts1 = new TestSleep(); TestSleep ts2 = new TestSleep(); ts1.setPriority(8); //提高优先级 ts1.start(); ts2.start(); }}不同系统输出结果不同!-----------------------------------------------------------------------------------------银行帐户类:-----------------------------------------------------------------------------------------package com.tarena.day12.thread;public class Account implements Runnable{ private int count = 2000; public void run(){ //运行状态 int temp = 0; synchronized (this){//同步机制 temp = count; //取余额到本地 if (temp>=800) { //取钱过程 temp -= 800; } try { //模拟网络延迟 Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); }//就绪,只有一个线程,t2还在锁池中 count = temp; //写回数据库 //运行 } } //消亡,归还钥匙 public static void main(String[] args) throws InterruptedException { Account acc = new Account(); Thread t1 = new Thread(acc); //new Thread t2 = new Thread(acc); //new t1.start(); //就绪状态 t2.start(); //就绪状态 Thread.sleep(500); System.out.println(acc.count); }}输出结果:400-----------------------------------------------------------------------------------------同步: The Object Lock flag(对象锁标记):每个对象都有个一位的锁标记用(0/1)表示释放锁(还钥匙)1.同步语句结束(正常)2.有未捕获的异常抛出3.break同步语句块,return4.wait()方法调用同步的范围越小越好同步利用对象锁把并行转化成串行,但是会大量降低效率注意:同步时一定要同步一个逻辑整体,不要只同步一两个语句线程的用途:1.并行代码2.while(true){}3.如果有内存开销特别大的代码就放入线程4.需要等待用户输入的就放入线程1.ArrayList //不能直接支持同步,但可以同步 vector安全的(并行的)2.HashMap Hashtable3.StringBuffer StringBuilder 什么时候使用同步:1.多线程共享数据2.共享数据冲突3.同步语句块synchronized(this){}死锁(Deadlock):一个线程或多个线程等待一个对象锁的释放1.顺序上锁,不要回调,反向解锁下面方法属于对象,但是为线程服务 void notify() 唤醒在此对象监视器上等待的单个线程。 void notifyAll() 唤醒在此对象监视器上等待的所有线程。 void wait() 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。 void wait(long timeout) 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。 void wait(long timeout, int nanos) 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。教程P98的线程图1.当Running 时间片用完的时候会回到Runnable2.调用yield()也有可能回到Runnable阻塞:只有正在Running的程序才有阻塞,阻塞解除了会回到Runnable状态等待继续执行消亡:Running正常结束,有异常未捕获。 消亡的时候还钥匙对象锁池:当同步的时候就会立刻调入锁池,等待得到钥匙才能到Runnable等待池:当调用wait()的时候就会进入等待池,从等待池出来就会进对象锁池,等待钥匙才能Runnable 所以wait()方法必须在同步语句块内调用,只有在同步语句块中才能保证有钥匙 调用notifyAll()可以把线程从等待池里全部转移到对象池
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -