赞
踩
目录
join : 合并线程 ,多干线程合并为一个线程
- package com;
-
- /**
- * jion : 合并线程 , 多个线程合并为一个线程
- *
- * @author 人间失格
- * @data 2021年10月29日上午11:23:32
- */
- public class Thread_01_Join {
-
- public static void main(String[] args) {
- //创建线程对象
- Thread t1 =new Thread(new Processer_01());
- Thread t2 =new Thread(new Processer_01());
- //线程设置名字
- t1.setName("我是t1");
- t2.setName("是我t2");
-
- //启动线程
- t1.start();
- t2.start();
-
- //执行到join的时候 ,因为时t1调用的,所以main之后的代码,必须等t1执行完之后才能执行
- try {
- t1.join();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- for (int i = 0;i<5 ;i++){
- System.out.println(Thread.currentThread().getName()+" : " + i);
- }
- }
- }
- //接口线程
- class Processer_01 implements Runnable{
- //覆写run方法
- @Override
- public void run(){
- for(int i = 0 ; i<5 ; i++){
- //currentThread : 获取当前线程队象 getName : 获取当前线程的名字
- System.out.println(Thread.currentThread().getName()+" : "+ i);
- }
- }
- }
yield : 暂停当前正在执行的线程,并让其他线程执行
1. yield是静态方法, 写在那个线程里,就让那个线程让位
2. 给同等级的优先级让位 , 不同优先级不让位
3. 只让出当前执行的时间片, 下次让不让不一定(也就是说只能保证让一次位)
yield() 应该做的是让当前运行线程回到可运行状态 , 以允许有相同优先级的其他线程获得运行机会
因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行.
但是,实际中无法保证yield()达到让步目的, 因为让步的线程还有可能呗线程调度程序再次选中.
结论 : yield() 从未导致下属昵称转到等待/睡眠/阻塞状态.
在大多数情况下,yield() 将导致线程从运行状态转到可运行状态,但有可能没有效果
- public class Thread_02_Yield {
-
- public static void main(String[] args) {
- Thread t1 = new Processor_02();
- t1.start();
-
- for(int i=0;i<10;i++){
- System.out.println(Thread.currentThread().getName()+" : "+i);
- }
- }
- }
- class Processor_02 extends Thread{
- @Override
- public void run() {
- for (int i = 0; i < 10; i++) {
- if (i % 2 == 0) {
- Thread.yield();
- }
- System.out.println(getName()+" : "+i);
- }
- }
- }
多个线程执行的不确定性引起执行结果的不稳定
多个线程对账本的共享,会造成操作的不完整性,会破坏数据
线程同步 :
当多个线程同时操作同一个数据的时候,尤其是更改操作,为了保证数据的一致性和正确性,需要进行一定的保护
所以线程同步是一种数据安全机制
同步编译和异步编译
同步编译 : 线程之间不是独立的,相互有影响,必须一个个执行
异步编译 : 线程之间是独立的,相互吗,没有影响
以下程序 因为同时操作了某个数据,导致结果不正确
1. 可以使用 synchronized修饰符解决
使用方式 : public synchronized void m1(){} 使用synchronized的方法,
不能被多个线程同时执行
比如 访问该对象中的某一个加锁的成员方法,那么该队昂中所有加锁的成员方法全部锁定,
其他线程都无法访问,只能拍到等待,等待该线程执行结束,交出锁
比如访问一个类的加锁的静态方法,那么该类中所有加锁的静态方法 全部锁定
2. synchronized{} 语句块解决
synchronized(对象){ //这种方式是把该对象中所有加锁的
成员方法和代码块锁全部锁定
同步代码;
}
synchronized(类名.class){ //这种方式是把该类中所有加锁的
静态方法和代码块锁全部锁定
同步代码;
}
- package com;
-
- /**
- * 线程同步 :
- * 当多个线程同时操作同一个数据的时候,尤其是更改操作,为了保证数据的一致性和正确性,需要进行一定的保护
- *
- * 所以线程同步是一种数据安全机制
- *
- * 同步编译和异步编译
- *
- * 同步编译 : 线程之间不是独立的,相互有影响,必须一个个执行
- * 异步编译 : 线程之间是独立的,相互吗,没有影响
- *
- * 以下程序 因为同时操作了某个数据,导致结果不正确
- * 1. 可以使用 synchronized修饰符解决
- * 使用方式 : public synchronized void m1(){} 使用synchronized的方法,
- * 不能被多个线程同时执行
- *
- * 比如 访问该对象中的某一个加锁的成员方法,那么该队昂中所有加锁的成员方法全部锁定,
- * 其他线程都无法访问,只能拍到等待,等待该线程执行结束,交出锁
- *
- * 比如访问一个类的加锁的静态方法,那么该类中所有加锁的静态方法 全部锁定
- * 2. synchronized{} 语句块解决'
- * synchronized(对象){ //这种方式是把该对象中所有加锁的
- * 成员方法和代码块锁全部锁定
- * 同步代码;
- * }
- *
- * synchronized(类名.class){ //这种方式是把该类中所有加锁的
- * 静态方法和代码块锁全部锁定
- * 同步代码;
- * }
- *
- * @author 人间失格
- * @data 2021年10月29日下午6:31:29
- */
- public class Thread_03_Synchronization {
-
- public static void main(String[] args) {
- //创建A对象传入参数10 ,也就是i=10
- A a = new A(10);
- A a1 = new A(11);
- //创建线程对象 因为是接口类型所以用这样的创建对象的方法
- Thread t1 = new Thread(new Processor_03(a));
- Thread t2 = new Thread(new Processor_03(a));
- t1.setName("t1");
- t2.setName("t2");
- t1.start();
- t2.start();
-
- }
- }
- class Processor_03 implements Runnable {
- A a;
-
- public Processor_03(A a) {
- super();
- this.a = a;
- }
-
- @Override
- public void run() {
- a.m1();
- }
- }
- class A{
- int i ;
- //有参构造
- public A(int i) {
- super();
- this.i = i;
- }
- //方法锁
- // public synchronized void m1(){
- public synchronized void m1(){
- System.out.println("1--------------------1");
-
- try {
- //睡眠 会出现异常
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- i++;
- System.out.println(Thread.currentThread().getName()+" : "+i);
- System.out.println("2@@@@@@@@@@@@2");
- }
- }
- class Ticket implements Runnable {
- private int tick = 100;
- public void run() { while (true) {
- if (tick > 0) {
- System.out.println(Thread.currentThread ().getName() + "售出车票,tick号为:" + tick--);
- } else{
- break;
- }
- }
- }
- class TicketDemo {
- public static void main(String[] args) {
- Ticket t = new Ticket();
- Thread t1 = new Thread(t);
- Thread t2 = new Thread(t);
- Thread t3 = new Thread(t);
- t1.setName("t1窗口");
- t2.setName("t2窗口");
- t3.setName("t3窗口");
- t1.start();
- t2.start();
- t3.start();
- }
- }
理想状态:
极端状态 :
- private int tick = 100;
- public void run(){
- while(true){
- if(tick>0){
- try{
- Thread.sleep(10);
- }catch(InterruptedException e){
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName()+“售出车票,tick号为:"+tick--);
- }
- }
- }
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有 执行完,另一个线程参与进来执行。导致共享数据的错误。
3.解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以 参与执行。
Synchronized的使用方法
synchronized (对象){
// 需要被同步的代码;
}
例如:
public synchronized void show (String name){
….
}
同步锁机制:
在《Thinking in Java》中,是这么说的:对于并发工作,你需要某种方式来防 止两个任务访问相同的资源(其实就是共享资源竞争)。 防止这种冲突的方法 就是当资源被一个任务使用时,在其上加锁。第一个访问某项资源的任务必须 锁定这项资源,使其他任务在其被解锁之前,就无法访问它了,而在其被解锁 之时,另一个任务就可以锁定并使用它了。
无法保证共享资源的安全
释放锁的操作
不会释放锁的操作
应尽量避免使用suspend()和resume()来控制线程
1. 从JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当。
2. java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的 工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象 加锁,线程开始访问共享资源之前应先获得Lock对象。
3. ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和 内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以 显式加锁、释放锁。
优先使用顺序:
Lock 同步代码块(已经进入了方法体,分配了相应资源)同步方法(在方法体之外)
-
- class A{
- private final ReentrantLock lock = new ReenTrantLock(); public void m(){
- lock.lock();
- try{
- //保证线程安全的代码;
- }
- finally{
- lock.unlock();
- }
- }
- }
- 注意:如果同步代码有异常,要将unlock()写入finally语句块
- package com;
-
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
-
- /**
- * JDK5.0 提出 : 代码块锁,性能较好
- * 又称位显示锁, 因为 开启和关闭 都是手动的
- * synchronized 是隐式锁,因为执行完全自动解锁
- *
- * @author 人间失格
- * @data 2021年10月29日下午6:57:13
- */
- public class Thread_04_Lock {
-
- public static void main(String[] args) {
- A1 a = new A1(10);
- Thread t1 = new Thread(new Processor_04(a));
- Thread t2 = new Thread(new Processor_04(a));
- t1.setName("t1");
- t2.setName("t2");
- t1.start();
- t2.start();
- }
- }
- class Processor_04 implements Runnable{
- A1 a ;
-
- public Processor_04(A1 a) {
- super();
- this.a = a;
- }
-
- @Override
- public void run() {
- a.m1();
- }
- }
- class A1{
- int i ;
-
- public A1(int i) {
- super();
- this.i = i;
- }
- //创建锁对象 Lock显式锁
- Lock lock = new ReentrantLock();
- public void m1(){
- System.out.println("@@@@@@");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- //开始加锁
- lock.lock();
- i++;
- System.out.println(Thread.currentThread().getName()+" : "+i);
- //解锁
- lock.unlock();
- System.out.println("==========");
- }
- }
- package com;
-
- import java.text.ParseException;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import java.util.Timer;
- import java.util.TimerTask;
-
- /**
- * 定时器
- * @author 人间失格
- * @data 2021年10月29日下午7:11:01
- */
- public class Thread_05_Timer {
-
- public static void main(String[] args) throws ParseException {
- //创建定时器
- Timer timer = new Timer();
- //1. 做什么事
- //2. 开始时间 ,可以是时间(到了指定时间开始u执行), 也可以是毫秒数(当前时间开始,多长时间之后开始执行)
- //3. 执行的间隔时间
- //两秒之后开始执行,并且每隔1秒执行一次
- // timer.schedule(new LogTimerTask(), 2000, 1000);
- long m =System.currentTimeMillis();
- m+=1000*60;
- String string ="2021-10-29 19:30:00 000";
- Date d =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").parse(string);
- timer.schedule(new LogTimerTask(), d, 1000);
- }
- }
- //任务类
- class LogTimerTask extends TimerTask{
-
- @Override
- public void run() {
- System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()));
- }
-
- }
死锁 : 在执行过程中,都遇到了加锁的功能,从而进入等待状体,导致大家都访问不了
1. 某个线程执行完成,需要 先后 嵌套 锁定 两个对象
2. A线程 先进入第一个对象,并锁定第一个对象,在第一个对象中去嵌套访问并锁定第二个对象
3. B线程,先进入第二个对象,并锁定第二个对象,在第二个对象中去嵌套访问并锁定第一个对象
4. 当A线程把第一个对象锁定之后,要去访问第二个对象的时候
发现已经被B线程锁住了,只能等待B线程交出第二个对象的锁才才能执行
5. 当B线程把第二个对象锁定之后,要去访问第一个对象的时候,
发现已经被A线程锁住了,只能等待A线程交出第一个对象的锁才能执行
6. 因此 导致A和B都进入等待状态
- public class Thread_06_DeadLock {
-
- public static void main(String[] args) {
- Object o1 = new Object();
- Object o2 = new Object();
-
- Thread t1 = new T1(o1,o2);
- Thread t2 = new T2(o1, o2);
- t1.start();
- t2.start();
-
- }
- }
- class T1 extends Thread{
- Object o1 ;
- Object o2 ;
- public T1(Object o1, Object o2) {
- super();
- this.o1 = o1;
- this.o2 = o2;
- }
- @Override
- public void run() {
- super.run();
- synchronized(o1){
- System.out.println("t1已经进入o1 准备进入o2");
-
- synchronized(o2){
- System.out.println("t1执行完成");
- }
- }
- }
- }
- class T2 extends Thread{
- Object o1 ;
- Object o2 ;
- public T2(Object o1, Object o2) {
- super();
- this.o1 = o1;
- this.o2 = o2;
- }
- @Override
- public void run() {
- super.run();
- System.out.println("@@@@@@@");
- synchronized(o2){
- System.out.println(" t2已经进入o2 准备进入o1");
-
- synchronized(o1){
- System.out.println("t2执行完成");
- }
- }
- }
- }
-
包含:
- package com;
-
- /**
- * 交叉执行
- *
- * wait : 让当前线程进入等待状态, 无参 或者传入 0 都意味着 不可以自动醒来,
- * 只能被唤醒,也可以传入毫秒数,到时间自动醒
- * notifyAll : 唤醒在当前对象中等待的所有线程
- * notify : 唤醒在当前对象中等待的某一个线程(不确定是那个)
- *
- * 以上两种方法必须用在成员加锁的方法中
- *
- * @author 人间失格
- * @data 2021年10月29日下午3:51:12
- */
- public class Thread_07_Wait {
-
- public static void main(String[] args) {
- //创建num对象
- Num num = new Num();
- //创建线程对象
- Thread t1 = new PrintOdd(num);
- Thread t2 = new PrintEven(num);
- //命名
- t1.setName("t1");
- t2.setName("t2");
- //启动
- t1.start();
- t2.start();
-
- }
- }
- class PrintOdd extends Thread{
- Num num;
-
- public PrintOdd(Num num) {
- super();
- this.num = num;
- }
- @Override
- public void run(){
- while(true){
- num.printOdd();
- }
- }
- }
-
- class PrintEven extends Thread{
- Num num;
-
- public PrintEven(Num num) {
- super();
- this.num = num;
- }
- @Override
- public void run(){
- while(true){
- num.printEven();
- }
- }
- }
-
- //业务类
- class Num{
- int count = 1;
- public synchronized void printOdd(){
- System.out.println(Thread.currentThread().getName()+" : "+count);
- count++;
- this.notifyAll();
- try {
- Thread.sleep(500);
-
- //挂起 交出该对象持有的锁 , 让其他线程可以执行
- this.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- public synchronized void printEven(){
- System.out.println(Thread.currentThread().getName()+" : "+count);
- count++;
- this.notifyAll();
- try {
- Thread.sleep(500);
-
- //挂起 交出该对象持有的锁 , 让其他线程可以执行
- this.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。