JAVA进阶知识点总结 6-线程 同步 线程状态
01.第一章:多线程_回顾实现线程的方式一:
1).定义一个线程类,继承自Thread,重写run()方法;
class MyThread extends Thread{ public void run(){ ... } }
2).启动线程
1).创建我们定义线程类的对象;
2).调用对象的start()方法启动线程;
main(){ MyThread t = new MyThread(); t.start(); // t.run();//只是普通的方法调用 }
02.第一章:多线程_多线程的运行原理:
03.第一章:多线程_Thread类的常用方法_构造方法:
1).构造方法:
1).Thread():无参构造方法
2).Thread(String name):使用一个线程名称构造一个线程对象
每个线程都有一个默认的线程名:Thread-索引值 通过getName()方法可以获取线程名称
3).Thread(Runnable run):使用一个Runnable的实现类构造一个线程对象; 在“创建线程的方式二”中演示
4).Thread(Runnable run,String name):使用一个Runnable和一个线程名称构造一个线程对象。
03.第一章:多线程_Thread类的常用方法_成员方法:
1).public String getName():获取线程的名称;
2).public static void sleep(long millis):让当前线程休眠指定的毫秒值;
public class MyThread extends Thread { @Override public void run() { for (; ; ) { Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String str = sdf.format(date); System.out.println(str); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
3).public static Thread currentThread():获取当前的线程对象;
public class Demo { public static void main(String[] args) { //主线程也是一个线程,是由JVM来启动的 //主线程也有线程名 //Thread.currentThread()可以获取当前的线程对象,然后调用getName()就能获取线程名称 for (int k = 0; k < 100; k++) { System.out.println(Thread.currentThread().getName() + " k = " + k); } } }
04.第一章:多线程_制作线程的方式二_Runnable接口:
1).定义一个子类,实现Runnable接口,重写run()方法;
/*
注意:实现Runnable后,我们的类–不是一个线程类
后期必须要委托给一个线程类Thread去执行
*/
public class MyRun implements Runnable { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + " i = " + i); } } }
2).启动线程:
1).创建一个自定义Runnable子类对象;
2).创建一个Thread对象,并将自定义对象作为参数传给Thread的构造方法;
3).调用Thread的start()方法启动线程。它内部会去调用我们自定义对象内部的run()方法。
示例代码:
public class Demo { public static void main(String[] args) { MyRun myRun = new MyRun(); Thread t1 = new Thread(myRun,"章子怡"); Thread t2 = new Thread(myRun,"汪峰"); t1.start(); t2.start(); } }
05.第一章:多线程_两种实现方式的区别:
1).第一种:继承自Thread.由于Java单继承的限制,对于子类形成了制约。
2).第二种:实现接口Runnable。子类可以同时实现多个接口【建议使用】
06.第一章:匿名内部类的方式实现线程:
1).匿名内部类的格式:
new 父类/父接口名(){ //子类的类体 }
2).实现线程的方式一,使用匿名内部类的方式:
new Thread(){//Thread的子类类体}.start();
示例代码:
public static void main(String[] args) { //Thread t = new Thread的匿名子类对象(); new Thread(){ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("i = " + i); } } }.start(); //主线程继续 for (int k = 0; k < 100; k++) { System.out.println("k = " + k); } }
2).实现线程的方式二,使用匿名内部类的方式:
new Thread(Runnable子类对象).start();
示例代码:
new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("i = " + i); } } }).start();
07.第一章:多线程安全性问题:
1).多线程安全性问题产生的原因:多个线程同时访问同一个变量;
2).示意图:
3).代码:
1.定义一个类,实现Runnable接口:
/*
注意:实现Runnable后,我们的类–不是一个线程类
后期必须要委托给一个线程类Thread去执行
*/
public class MyRun implements Runnable { int a = 100; @Override public void run() {//线程1,线程2 for (int i = 0; i < 100; i++) {//线程1(1,2)//线程2(1,2,3)//线程1(3) a++;//1.将a的值100取出到运算器中;2.在运算器中计算 100 + 1 ;3.将101赋给a } System.out.println("线程执行完毕!"); } }
2.测试类:
public class Demo { public static void main(String[] args) throws InterruptedException { MyRun myRun = new MyRun(); Thread t1 = new Thread(myRun,"章子怡"); Thread t2 = new Thread(myRun,"汪峰"); t1.start(); t2.start(); //主线程休息一秒,确保上面的两个线程执行完毕 Thread.sleep(1000); //获取最终的结果 System.out.println(myRun.a);//正常:300 } }
08.第二章:多线程售票模拟线程安全性问题:
1).定义Tickets类:
public class Tickets implements Runnable { private int tickets = 100; @Override public void run() { //死循环 while (true){ //判断是否有票 if (tickets > 0) { //取一张 int t = tickets; try { Thread.sleep(1);//目的:让效果更明显,让其它线程运行 } catch (InterruptedException e) { e.printStackTrace(); } tickets--; System.out.println(Thread.currentThread().getName() + " 取走一张票:" + t); }else{ System.out.println("没票了!"); break; } } } }
2).定义测试类:
public class Demo { public static void main(String[] args) { //1.创建一个Tickets对象 Tickets t = new Tickets(); //2.创建两个线程 Thread t1 = new Thread(t,"窗口1"); Thread t2 = new Thread(t,"窗口2"); t1.start(); t2.start(); } }
09.第二章:同步代码块_解决多线程售票线程安全性问题:
1).格式:
synchronized(锁对象){
//同步代码
}
锁对象:可以是任何对象,但必须保证多个线程共同使用同一个锁对象。
2).示例代码:
1).修改Tickets类:
public class Tickets implements Runnable { private int tickets = 100; private Object obj = new Object(); @Override public void run() { while (true){ synchronized (obj){ if (tickets > 0) { int t = tickets; try { Thread.sleep(1);//目的:让效果更明显 } catch (InterruptedException e) { e.printStackTrace(); } tickets--; System.out.println(Thread.currentThread().getName() + " 取走一张票:" + t); }else{ System.out.println("没票了!"); break; } }//一个线程执行完毕,会自动释放锁 } } }
2).主线程类:
public class Demo { public static void main(String[] args) { //1.创建一个Tickets对象 Tickets t = new Tickets(); //2.创建两个线程 Thread t1 = new Thread(t,"窗口1"); Thread t2 = new Thread(t,"窗口2"); t1.start(); t2.start(); } }
10.第二章:同步方法_解决多线程售票线程安全性问题【常用】:
1).格式:
//同步方法,使用的锁对象是:this
public synchronized int getTicket(){
//同步代码
}
2).示例代码:
1).修改Tickets类即可:
public class Tickets implements Runnable { private int tickets = 100; @Override public void run() { while (true){ int t = this.getTicket(); if (t > 0) { System.out.println(Thread.currentThread().getName() + " 取走一张票:" + t); }else{ System.out.println("没票了!!"); break; } } } //同步方法,使用的锁对象是:this public synchronized int getTicket() { if (tickets > 0) { int t = tickets; try { Thread.sleep(1);//目的:让效果更明显 } catch (InterruptedException e) { e.printStackTrace(); } tickets--; return t; } else { return 0; } } }
11.第二章:Lock锁_解决多线程售票线程安全性问题:
1).格式:
Lock l = new 某个实现类对象(); l.lock();//加锁 try { //同步代码 } finally { l.unlock(); //解锁 }
2).示例代码:
public class Tickets implements Runnable { private int tickets = 100; private Lock lock = new ReentrantLock(); @Override public void run() { while (true){ lock.lock();//加锁 try { if (tickets > 0) { int t = tickets; try { Thread.sleep(1);//目的:让效果更明显 } catch (InterruptedException e) { e.printStackTrace(); } tickets--; System.out.println(Thread.currentThread().getName() + " 取走一张票:" + t); } else { System.out.println("没票了!"); break; } }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock();//解锁 } } } }
12.第三章:线程状态:
13.第三章:线程状态_无限等待_wait方法:
public class Demo { public static void main(String[] args) throws InterruptedException { Object obj = new Object(); new Thread(){ @Override public void run() { synchronized (obj) { for (int i = 0; i < 20; i++) { System.out.println("i = " + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (i == 10) { //让当前的线程挂起,等待被唤醒 try { System.out.println("我开始等待..."); obj.wait();//会立即释放obj锁 System.out.println("我醒了,开始干活了...."); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }.start(); //开启一个新线程 new Thread(){ @Override public void run() { //获取obj锁对象 System.out.println("第二个线程开始执行..."); synchronized (obj){ //唤醒所有在obj锁上等待线程. System.out.println("第二个线程开始唤醒...."); obj.notifyAll();//唤醒后, }//唤醒后,会释放锁 } }.start(); }}
14.第三章:线程状态_无限等待_包子铺案例:
=======================================================================
学习目标总结:
01.能够描述Java中多线程运行原理
每一个执行线程都有一片自己所属的栈内存空间。进行方法的压栈和弹栈
02.能够使用继承类的方式创建多线程
class MyThread extends Thread{ public void run(){ //... } } main(){ MyThread t = new MyThread(); t.start(); t.run();//普通的方法调用 t.start();//抛异常 }
03.能够使用实现接口的方式创建多线程
class MyRun implements Runnable{ public void run(){ //... } } main(){ MyRun myRun = new MyRun(); Thread t = new Thread(myRun); t.start(); }
04.能够说出实现接口方式的好处
1).解决单继承的限制。
05.能够解释安全问题的出现的原因
1).多个线程同时访问同一个变量;
06.能够使用同步代码块解决线程安全问题
synchronized(锁对象){
//同步代码
}
07.能够使用同步方法解决线程安全问题
public synchronized void show(){ //同步代码 }
08.能够说出线程6个状态的名称
1.新建
2.可运行
3.计时等待
4.锁阻塞
5.无限等待
6.被终止
09.能够理解等待唤醒案例
public static void main(String[] args) throws InterruptedException { Object obj = new Object(); new Thread(){ @Override public void run() { synchronized (obj) { for (int i = 0; i < 20; i++) { System.out.println("i = " + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (i == 10) { //让当前的线程挂起,等待被唤醒 try { System.out.println("我开始等待..."); obj.wait();//会立即释放obj锁 System.out.println("我醒了,开始干活了...."); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }.start(); //开启一个新线程 new Thread(){ @Override public void run() { //获取obj锁对象 System.out.println("第二个线程开始执行..."); synchronized (obj){ //唤醒所有在obj锁上等待线程. System.out.println("第二个线程开始唤醒...."); obj.notifyAll();//唤醒后, }//唤醒后,会释放锁 } }.start(); }
- Java多线程知识点总结——进阶篇(四)之静态同步函数用的是哪一个锁问题
- 由单例模式的优化,引出的java线程数据同步和类加载顺序知识点总结
- Java多线程知识点总结——进阶篇(十一) 之 守护线程(后台运行)
- java线程状态转换/同步与锁
- Java知识点总结篇:Java的内存模型、线程安全、进程和线程的区别
- Java线程同步管理的相关概念总结
- Java线程总结(二):线程的同步方式synchronized
- Java线程同步方法实例总结
- java核心知识点学习----并发和并行的区别,进程和线程的区别,如何创建线程和线程的四种状态,什么是线程计时器
- 与线程有关的知识点总结 java
- Java基础-23总结多线程,线程实现Runnable接口,线程名字获取和设置,线程控制,线程安全,同步线程
- 进程、线程知识点总结和同步(消费者生产者,读者写者三类问题)、互斥、异步、并发、并行、死锁、活锁的总结
- JAVA进阶知识点总结(3)— 多线程
- Java进阶之支付宝在线支付知识点总结
- Java线程状态知识点
- java线程总结1--线程的一些概念基础以及线程状态
- Java进阶之多级联下拉列表知识点总结
- Java总结(十)—实现Runnable接口创建线程,线程安全同步,死锁(哲学家进餐问题),读写锁
- java进阶 线程池 join用法总结:thread4.join();方法,就表明thread4.join();这个线程受到贵客待遇,直到这个线程执行完,被插入这个方法的载体线程才可以执行。
- java线程同步问题的总结