多线程

发布于:2023-02-01 ⋅ 阅读:(684) ⋅ 点赞:(0)

 锁:

Synchronized,多线程并发编程

package morning;


public class SynchronizedUse {

    //同步普通方法,只能用在单例上,同一个实例只有一个线程能获取锁进入这个方法
    public synchronized void method(){
        System.out.println(1);
    }
    /*
    同步静态方法,无论有多少实例,同时只能有一个线程能获取锁然后
     进入这个方法,是类级别的锁,一旦任何一个线程进入这个方法,其他所有线程将无法
     访问这个类的任何同步类锁的方法
     */
    public synchronized static void method2(){};
/*
 同步类,以下两种是同步块的用法,表示只有获取到这个类锁才能进入这个代码块
 */
    public void s(){
        synchronized (SynchronizedUse.class){}
    }
    public void s2(){
        synchronized (this.getClass()){}
    }
    /*
    同步this实例,表示锁住整个当前对象实例,只有获取到这个实例的锁才能进入这个方法,
    用法和同步普通方法一样,都是锁住整个当前实例
     */
    public void s3(){
        synchronized (this){}
    }
    /*
    类锁与实例锁不相互阻塞,但相同的当前实例锁,相同的类锁,相同的对象锁会相互阻塞
     */
}

重量级所,jdk1.6对synchronized进行了优化

jdk1.6为了减少获得锁和释放锁带来的性能消耗引入的偏向和轻量级锁

三种方式加锁

1,修饰实例方法,作用于当前实例加锁,进入同步代码之前获得当前实例的锁

2,静态方法,作用于当前类对象加锁,进入同步代码前要获得的是当前类对象的锁

3,代码块,指定加锁对象,给指定对象加锁,进入代码块之前要获得给定对象的锁

1,实例方法,调用该方法的实例

2,静态方法,类对象,类名.class

3,this,调用该方法的实例对象

4,类对象,类对象 (推荐使用)

关于同步方法:

同步方法依然会涉及到同步锁对象,不需要我们写出来

非静态的同步方法,同步锁就是this

静态的同步方法,同步监视器就是类本身

同步代码块

选好同步监视器,推荐使用类对象,第三方对象this

在实现接口创建的线程类中,同步代码块不可以用this来充当同步锁

同步的方式,解决了线程安全的问题,操作同步代码块时,只有一个线程能参与,其他线程等待,相当于一个单线程的过程,效率低

synchronize只针对当前的jvm可以解决线程安全的问题

synchronize不可以跨jvm解决问题

死锁:

多个线程同时被阻塞,他们中的一个或者全部都在等待某个资源的释放,由于线程无限制的阻塞,程序就不可能正常终止

java中死锁产生条件

1,互斥使用,当资源被一个线程使用,别的线程不能使用

2,不可抢占,资源请求者不能从占有者中抢夺资源,资源只能从占有者主动释放

3,请求和保持,,

4,循环等待,存在一个等待的队列,p1占有p2的资源 p2占有p3的资源p2占有p3的资源,形成一个等待环路

互相占有对方的资源但是都不释放

class LockA implements Runnable {

    @Override
    public void run() {
        System.out.println(new Date().toString() + "LockA开始执行...");
        try {
            while (true) {
                synchronized (Ch04.obj1) {
                    System.out.println(new Date().toString() + "LockA锁住了obj1");

                    Thread.sleep(8000);
                }
                synchronized (Ch04.obj2) {
                    System.out.println(new Date().toString() + "LockA锁住了obj2");
                    Thread.sleep(70*1000);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
    class LockB implements Runnable {

        @Override
        public void run() {
            System.out.println(new Date().toString() + "LockB开始执行...");
            try {
                while (true) {
                    synchronized (Ch04.obj2) {
                        System.out.println(new Date().toString() + "LockB锁住了obj2");
                        Thread.sleep(6000); //3s
                    }
                    synchronized (Ch04.obj1) {
                        System.out.println(new Date().toString() + "LockB锁住了obj1");
                        Thread.sleep(100*1000); // 1min
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public class Ch04 {
        public static String obj1 = "obj1";
        public static String obj2 = "obj2";

        public static void main(String[] args) {
            LockA lockA = new LockA();
            new Thread(lockA).start();
            LockB lockB = new LockB();
            new Thread(lockB).start();
        }
    }

线程重入

任意线程在拿到锁之后,再次获取该锁不会被该锁所阻碍

线程不会被自己锁死,SYNCHRONIZED可重入锁


    private static final Object M1 = new Object();
    private static final Object M2 = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (M1) {
                synchronized (M2) {
                    synchronized (M1) {
                        synchronized (M2){
                            System.out.println("hello lock");
                        }
                    }
                }
            }
        }).start();
    }
}

jdk1.6之后锁升级

1,无锁,不加锁

2,偏向锁,不锁锁,当只有一个线程争夺时,偏向某一个线程,这个线程不加锁

3,轻量级锁,少量线程来了之后,先尝试自旋,不挂起线程,

4,重量级锁,排队挂起(暂停)线程(synchronized)

挂起线程和恢复线程需要转入内核态中完成这些操作,给系统的并发性带来很大压力,

在许多应用上共享数据的锁定状态,只会持续很短的时间,为了这段时间去恢复和挂起并不值得,让后面的线程等一下,不要放弃处理器的执行时间,锁为了让线程等待,让线程形成一个循环,自旋(自旋锁)


Object类

wait(); 不叫不能进来

wite(long timeout):让当前线程进入等待状态  到时间自己进来,或者叫

notify():唤醒正在等待的下一个线程  叫

notifyall();唤醒正在等待的所有线程  叫所有人进来

线程间的通信:

比如两条线程共同运行,如果线程a先走,线程b就要等待,等a走完,唤醒b,b再走

方法的总结:

1,thread的两个静态方法

sleep释放cpu资源,但是不会释放锁

yield释放cpu的执行权,但是保留了cpu的执行资格,不常用

join方法:插队,出让了执行权,join就加入进来

wait:释放资源,释放锁

面试题:sleep和wait的区别?


线程的退出

使用退出标志,让线程正常退出run方法结束后线程终止

interrupt方法:中断线程

* 调用interrupt方法会抛出InterruptedException异常,
 *  捕获后再做停止线程的逻辑即可。
 *
 *  如果线程while(true)运行的状态,interrupt方法无法中断线程。


class MyThread02 extends Thread {

    private boolean flag = true;

    @Override
    public void run() {
        while(flag) {
            synchronized (this){
//                try {
//                    wait();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                try {
                    sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    this.stopThread();
                }
            }
        }
    }
    public void stopThread() {
        System.out.println("线程停止运行...");
        this.flag = false;
    }
}
public class Ch04 {

//    public void show() {
//        try {
//            wait();
//            // 线程异常终止     异常
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//    }

    public static void main(String[] args) {
        MyThread02 myThread02 = new MyThread02();
        myThread02.start();

        System.out.println("线程开始...");

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 中断线程的执行
        myThread02.interrupt();
    }
}

线程的常用方法:
 * Thread类中的方法
 * 1.start:启动当前线程;执行run方法
 * 2.run:
 * 3.currentThread:静态方法,获取当前正在执行的线程
 * 4.getId():返回此线程的唯一标识
 * 5.setName(String):设置当前线程的name
 * 6.getName():获取当前线程的name
 * 7.getPriority():获取当前线程的优先级
 * 8.setPriority(int):设置当前线程的优先级
 * 9.getState():获取当前线程的声明周期
 * 10.interrupt():中断线程的执行
 * 11.interrupted():查看当前线程是否中断

package eveing;

public class Test {
    public static void main(String[] args) {
        Thread thread=Thread.currentThread();
        System.out.println(thread);
        MyThread thread1=new MyThread();
        thread1.start();
        thread1.setDaemon(true);
        System.out.println(thread1.isDaemon());
    }
}
class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(getId());
        setName("线程一");
        System.out.println(getName());

    }
}

valied修饰属性的两个作用

1,不许指令重排

2,不进缓存

synchronized锁的单例模式(线程安全)
 

package eveing;

public class Singleton {
    private static Singleton instant;
    private Singleton(){}
    public static Singleton getInstance(){
        if(instant==null){
            synchronized (Singleton.class){
                if(instant==null){
                    instant=new Singleton();
                }
            }
        }
        return instant;
    }
    
}


网站公告

今日签到

点亮在社区的每一天
去签到