一切为了自己,写下自己的线程总结

only老K,我为自己代言

概述

What is 线程?(有点拉跨这个英语水平)
在这里插入图片描述
进入主题:
面试中,多线程和并发编程已经是必不可少的了,我经常看到此类问题,当时也简单了解过,什么继承Thread类,实现Runnable接口,这些都被说烂了,知道这些当然是远远不够的,于是这几天搜索相关资料恶补了一下,为了方便后期复习,在此做个总结。

继承Thread类

package com.onlyk.domexc.DomeOne;

/**
 * @author only老K 我为自己代言
 * @create 2020-06-21 20:02
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class TestThread {
    public static void main(String[] args) {
        new MyThread().start();
        System.out.println("!!!");
        new Thread(new MyThread()).start();
    }
}
class MyThread extends Thread{
    @Override
    public void run() {
        String name="only老K,我为自己代言";
        String[] split = name.split(",");
        for (String s : split) {
            System.out.println(s+"!!");
        }
    }
}

实现Runnable接口

package com.onlyk.domexc.DomeOne;

/**
 * @author only老K 我为自己代言
 * @create 2020-06-21 20:02
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class TestThread {
    public static void main(String[] args) {
//        new MyThread().start();
//        new Thread(new MyThread()).start();
        new MyRunnable().run();
        new Thread(new MyRunnable()).start();
        new Thread(new MyRunnable(),"only老K").start();
    }
}
class MyRunnable implements Runnable {
    @Override
    public void run() {
      String name="only老K,我为自己代言";
        String[] split = name.split(",");
        for (String s : split) {
            System.out.println(s+"@@@");
        }
    }
}

或者使用匿名内部类

package com.onlyk.domexc.DomeOne;

/**
 * @author only老K 我为自己代言
 * @create 2020-06-21 20:02
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class TestThread {
    public static void main(String[] args) {
//        new MyThread().start();
//        new Thread(new MyThread()).start();
//        new MyRunnable().run();
//        new Thread(new MyRunnable()).start();
//        new Thread(new MyRunnable(),"only老K").start();
        //使用匿名内部类
        new Thread(new Runnable() {
            @Override
            public void run() {
                String name="匿名内部类的方式,来创实现";
                System.out.println(name);
            }
        }).start();
    }
}
class MyThread extends Thread{
    @Override
    public void run() {
        String name="only老K,我为自己代言";
        String[] split = name.split(",");
        for (String s : split) {
            System.out.println(s+"!!");
        }
    }
}
class MyRunnable implements Runnable {
    @Override
    public void run() {
      String name="only老K,我为自己代言";
        String[] split = name.split(",");
        for (String s : split) {
            System.out.println(s+"@@@");
        }
    }
}

通过Lamata表达式

package com.onlyk.domexc.DomeOne;

/**
 * @author only老K 我为自己代言
 * @create 2020-06-21 20:02
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class TestThread {
    public static void main(String[] args) {
//        new MyThread().start();
//        new Thread(new MyThread()).start();
//        new MyRunnable().run();
//        new Thread(new MyRunnable()).start();
//        new Thread(new MyRunnable(),"only老K").start();
        //使用匿名内部类
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                String name="匿名内部类的方式,来创实现";
//                System.out.println(name);
//            }
//        }).start();
        //通过Lamata表达式
        new Thread(()->{
            System.out.println("表达式");
        }).start();
    }
}
class MyThread extends Thread{
    @Override
    public void run() {
        String name="only老K,我为自己代言";
        String[] split = name.split(",");
        for (String s : split) {
            System.out.println(s+"!!");
        }
    }
}
class MyRunnable implements Runnable {
    @Override
    public void run() {
      String name="only老K,我为自己代言";
        String[] split = name.split(",");
        for (String s : split) {
            System.out.println(s+"@@@");
        }
    }
}

实现Callable

package com.onlyk.domexc.DomeOne;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @author only老K 我为自己代言
 * @create 2020-06-22 20:45
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class TestCallable {
    public static void main(String[] args) throws Exception{
        //创建执行服务
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //提交执行
        Future submit1 = executorService.submit(new MyCallable());
        Future submit2 = executorService.submit(new MyCallable());
        Future submit3 = executorService.submit(new MyCallable());
        //获取返回值
        Object o1 = submit1.get();//这里需要抛出异常,可以进到get方法中看
        Object o2 = submit2.get();
        Object o3 = submit3.get();
        System.out.println(o1);
        System.out.println(o2);
        System.out.println(o3);
        //关闭服务,不然控制台会一直跑
        executorService.shutdown();
    }
}
class MyCallable implements Callable {
    @Override
    public Object call() {
        for (int i = 0; i < 10 ;i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
        return true;
    }
}

线程状态

在这里插入图片描述

创建状态
所谓的创建状态,也就是我们的new Thread();
就绪状态
所谓的就绪状态,就是我们myThread.start();
运行状态
运行状态就是我们的代码执行。
阻塞状态
当线程等待(wait)、同步(synchronized)、sleep和join的时候
死亡状态
run()结束、main()结束
线程常用方法
setPriority(int new Priority)更改线程的优先级
sleep(long millis)让当前线程进入休眠
join()相当于插队,插入的线程执行结束后,被插队线程继续执行。
yield()线程礼让,暂停当前的线程,并把该线程状态转化为就绪状态
interrupt()中断线程(不建议用)
isAlive()判断线程是否处于存活状态

手写多线程案例

package com.onlyk.domexc.DomeOne;

/**
 * @author only老K 我为自己代言
 * @create 2020-06-22 20:50
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class Dome {
    public static void main(String[] args) {
        DomeRunnable domeRunnable=new DomeRunnable();
        new Thread(domeRunnable,"one").start();
        new Thread(domeRunnable,"two").start();
        new Thread(domeRunnable,"three").start();
    }
}
class DomeRunnable implements Runnable{
    private int num=20;
    private boolean flag=true;
    public void run() {
        while (flag){
            go();
        }
    }
    public void go(){
        if(num <=0){
            flag=false;
            return;
        }
        try {
            Thread.sleep(100);
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ":"+ num--);
    }
}

看图片,很显然有重复的操作
在这里插入图片描述
正常来说我们要做到的是减到0就不会在减少了。
可以看出,出现了线程安全问题,原因是在对num变为0之前,有多个线程同时进来。
解决办法,可以通过synchronized线程同步,可以使用同步方法和同步代码块进行解决。同步方法,也就是在方法上加一个synchronized关键字。

   public synchronized void run() {
      while (flag){
          go();
      }
    }

随便你怎么刷新都是一样的
在这里插入图片描述

同步代码块锁的是一个对象,即是需要变化的量

package com.onlyk.domexc.DomeOne;

/**
 * @author only老K 我为自己代言
 * @create 2020-06-22 20:50
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class Dome {
    public static void main(String[] args) {
        DomeRunnable domeRunnable=new DomeRunnable();
        new Thread(domeRunnable,"one").start();
        new Thread(domeRunnable,"two").start();
        new Thread(domeRunnable,"three").start();
    }
}
class DomeRunnable implements Runnable{
    MyNum myNum =new MyNum(20);
    private boolean flag=true;
    public synchronized void run() {
        while (flag){
            go();
        }
    }
    public void go(){
        if(myNum.num <=0){
            flag=false;
            return;
        }
        try {
            Thread.sleep(100);
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ":"+ myNum.num--);
    }
}
class MyNum{
    int num;
    public MyNum(int num){
        this.num=num;
    }
}

死锁

package com.onlyk.domexc.DomeOne;

/**
 * @author only老K 我为自己代言
 * @create 2020-06-22 20:58
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class DomeDIe {
    public static void main(String[] args){
        Only o=new Only();
        King k=new King();
        new Thread(new MyThread(o,k,0)).start();
        new Thread(new MyThread(o,k,1)).start();
    }
}
class Only{}
class King{}
class MyThread implements Runnable{
    private Only o;
    private King k;
    private int cccc;
    public MyThread(Only o,King k,int cccc){
        this.o=o;
        this.k=k;
        this.cccc=cccc;
    }
    public void run() {
        if(cccc == 0){
            synchronized (o){
                System.out.println(Thread.currentThread().getName()+"获取"+o);
                try {
                    Thread.sleep(1000);
                }catch (Exception e){

                }
                synchronized (k) {
                    System.out.println(Thread.currentThread().getName() + "获得" + k);
                }
            }
        }else{
            synchronized (k){
                System.out.println(Thread.currentThread().getName()+"获取"+k);
                try {
                    Thread.sleep(1000);
                }catch (Exception e){

                }
                synchronized (o) {
                    System.out.println(Thread.currentThread().getName() + "获得" + o);
                }
            }
        }
    }
}

一直在运行,占用CPU。导致死锁
在这里插入图片描述

Lock锁

Lock是一个接口,而不是一个关键字,他是一个显示锁,只能锁同步代码块,不能锁方法,可以显示加锁,释放锁,可以指定唤醒某一个线程,Lock锁有一个实现类是ReentrantLock,可重入锁(递归锁),在这里说一下,所有的锁都是可重入锁,也就是如果我们获得了外面的锁之后,会自动获取里面的锁。
下面代码正常情况下会出现线程安全问题。

package com.onlyk.domexc.DomeOne;

/**
 * @author only老K 我为自己代言
 * @create 2020-06-22 21:03
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class DomeLock {
    public static void main(String[] args){
     LockThread lockThread = new LockThread();
         new Thread(lockThread).start();
         new Thread(lockThread).start();
         new Thread(lockThread).start();
    }
}
class LockThread implements Runnable{
    private int num = 100;
    @Override
    public void run() {
        while (num > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(num --);
        }
    }
}

可以通过RenntrantLock进行加锁,显示锁,记得解锁。

package com.onlyk.domexc.DomeOne;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author only老K 我为自己代言
 * @create 2020-06-22 21:03
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class DomeLock {
    public static void main(String[] args){
     LockThread lockThread = new LockThread();
         new Thread(lockThread).start();
         new Thread(lockThread).start();
         new Thread(lockThread).start();
    }
}
class LockThread implements Runnable{
    private int num = 100;
    //定义一个Lock锁
    ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true) {
            lock.lock();
            if(num > 0){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(num --);
            }else{
                break;
            }
            lock.unlock();
        }
    }
}

比ReentrantLock更细的锁是,ReentrantReadWriteLock,这里有一个读锁,一个写锁,

package com.onlyk.domexc.DomeOne;

import java.util.HashMap;
import java.util.Map;

/**
 * @author only老K 我为自己代言
 * @create 2020-06-29 21:52
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class ReentrantLockDome {
    public static void main(String[] args) {
            MyReadWriteLock myReadWriteLock = new MyReadWriteLock();
            for (int i = 0; i < 5; i++) {
                int temp = i;
                new Thread(()->{
                    myReadWriteLock.put(temp + "",temp + "");
                },""+temp).start();
            }
            for (int i = 0; i < 5; i++) {
                int temp = i;
                new Thread(()->{
                    myReadWriteLock.get(temp + "");
                },temp + "").start();
            }
    }
}
class MyReadWriteLock{
    private volatile Map<String,String> map=new HashMap<String, String>();
    public void put(String key,String value){
        System.out.println(Thread.currentThread().getName()+"写"+key);
        map.put(key,value);
        System.out.println(Thread.currentThread().getName()+"写入完成");
    }
    public void get(String key){
        System.out.println(Thread.currentThread().getName()+"读"+key);
        map.get(key);
        System.out.println(Thread.currentThread().getName()+"读取完成");
    }
}

如果不加锁的话,在写入完成之前会被其他线程插入
如图

我们想要的是,在写入的时候,只能是一个线程,而读取的时候,可以是多个线程

package com.onlyk.domexc.DomeOne;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author only老K 我为自己代言
 * @create 2020-06-29 21:52
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class ReentrantLockDome {
    public static void main(String[] args) {
            MyReadWriteLock myReadWriteLock = new MyReadWriteLock();
            for (int i = 0; i < 5; i++) {
                int temp = i;
                new Thread(()->{
                    myReadWriteLock.put(temp + "",temp + "");
                },""+temp).start();
            }
            for (int i = 0; i < 5; i++) {
                int temp = i;
                new Thread(()->{
                    myReadWriteLock.get(temp + "");
                },temp + "").start();
            }
    }
}
class MyReadWriteLock{
    private volatile Map<String,String> map = new HashMap<>();
    ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    public void put(String key,String value) {
        readWriteLock.writeLock().lock();
        System.out.println(Thread.currentThread().getName() + "写入" + key);
        map.put(key,value);
        System.out.println(Thread.currentThread().getName() + "写入完成");
        readWriteLock.writeLock().unlock();
    }

    public void get(String key) {
        readWriteLock.readLock().lock();
        System.out.println(Thread.currentThread().getName() + "读取" + key);
        map.get(key);
        System.out.println(Thread.currentThread().getName() + "读取完成");
        readWriteLock.readLock().unlock();
    }
}

在这里插入图片描述

synchronized和Lock的区别

  • synchronized是关键字,Lock是类
  • synchronized无法获取锁的状态,Lock可以
  • synchronized会自动释放锁,Lock需要手动
  • synchronized没有Lock锁灵活(Lock锁可以自己定制)

只说理论是不行的,下面说几个ReentrantLock的场景

ReentrantLock默认是非公平锁,但它可以设置公平锁,也就是谁先来的谁先获得锁new ReentrantLock(true)。
ReentrantLock可以响应中断,也就是当两个线程发生死锁的时候,你把A线程中断了,B线程可以正常运行。
ReentrantLock可以通过tryLock()实现限时等待,这样可以解决死锁问题。
synchronized
synchronized在JDK1.6进行了锁的优化,也就是当一个线程多次访问一个同步代码块的时候,此时会记录该线程的threadId也就是,当你再来访问的时候,我就只需判断threadId就行了,效率高,这属于偏向锁。
当有多个线程来的时候,那么这个锁就会升级为轻量级锁,也就是通过CAS,来进行尝试获取锁,是一种自旋锁的状态。如果在短时间内可以获得锁,不会堵塞,而且节约了CUP上下文切换的时间。
如果长时间没有获取到锁,会消耗CUP的资源,因为在那一直死循环,经过一个时间段后会升级为重量级锁,会发生阻塞。其中锁升级是不可逆的。

生产者消费者问题

这是一个经典的线程通信问题,也就是不同线程之间有联系,生产者生产的东西放到缓冲区,如果缓冲区满了,生产者进入堵塞,缓冲区空了,消费者堵塞。
常用的方法有wait(),notify(),notifyAll()

package com.onlyk.domexc.Seven8;

/**
 * @author only老K 我为自己代言
 * @create 2020-07-08 12:26
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class dome {
        public static void main(String[] args) {
            Buffer buffer=new Buffer();
            new Thread(()->{
                for (int i = 0; i < 100; i++) {
                    System.out.println("生产者生产了" + i);
                    buffer.put();
                }
            },"生产者").start();
            new Thread(()->{
                for (int i = 0; i < 100; i++) {
                    System.out.println("消费者消费了" + i);
                    buffer.get();
                }
            },"消费者").start();
        }
    }
    //缓冲区
    class Buffer{
        private int len=0;
        public synchronized void put (){
            if (len < 10){
                len++;
            }else{
                try {
                    wait();
                }catch (Exception e){

                }
            }
            notifyAll();
        }
        public synchronized void get() {
            if (len > 0) {
                len --;
            } else {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            notifyAll();
        }
}

其中这里引入了Condition,他可以指定唤醒某个线程,这里我们演示三个线程ABC。

package com.onlyk.domeone.Thread;


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Main {
    public static void main(String[] args) {
        Buffer buffer = new Buffer();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                buffer.a();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                buffer.b();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                buffer.c();
            }
        },"C").start();
    }
}
// 缓冲区
class Buffer {
    private int flag = 1;// 1执行A,2执行B,3执行C
    Lock lock = new ReentrantLock();
    Condition condition1 = lock.newCondition();// 该对象可以设置一些条件
    Condition condition2 = lock.newCondition();// 该对象可以设置一些条件
    Condition condition3 = lock.newCondition();// 该对象可以设置一些条件

    public void a() {
        lock.lock();
        try {
            while (flag != 1) {
                condition1.await();
            }
            System.out.println("A");
            flag = 2;
            condition2.signal();// 指定唤醒B
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void b() {
        lock.lock();
        try {
            while (flag != 2) {
                condition2.await();
            }
            System.out.println("B");
            flag = 3;
            condition3.signal();// 指定唤醒C
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void c() {
        lock.lock();
        try {
            while (flag != 3) {
                condition3.await();
            }
            System.out.println("C");
            flag = 1;
            condition1.signal();// 指定唤醒A
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

在这里插入图片描述

八锁问题

一锁

package com.onlyk.domexc.Seven8;

import java.util.concurrent.TimeUnit;

/**
 * @author only老K 我为自己代言
 * @create 2020-07-08 7:49
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class dome1 {
    public static void main(String[] args) {
        Man man=new Man();
        new Thread(()->{
            man.go();
        }).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            man.in();
        }).start();
    }
}
class Man{
        public synchronized void go(){
            System.out.println("出去");
        }
        public synchronized void in(){
            System.out.println("进来");
        }
}

在这里插入图片描述
先输出出去,不要理解为是先调用了go(),而是因为上面线程先获得了锁。

二锁

class Man{
        public synchronized void go(){
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("出去");
        }
        public synchronized void in(){
            System.out.println("进来");
        }
}

结果还是一样的啊。这里的synchronized锁的对象是调用者,这两个方法用的是同一把锁,谁先拿到,谁先执行

三锁

class Man{
        public synchronized void go(){
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("出去");
        }
        public void in(){
            System.out.println("进来");
        }
}

这里in()方法是没有使用synchronized锁的了,等于就是先输出in()因为他不去获取锁资源,所以直接输出了

四锁

package com.onlyk.domexc.Seven8;

import java.util.concurrent.TimeUnit;

/**
 * @author only老K 我为自己代言
 * @create 2020-07-08 7:49
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class dome1 {
    public static void main(String[] args) {
        Man man=new Man();
        Man king=new Man();
        new Thread(()->{
            man.go();
        }).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            king.in();
        }).start();
    }
}
class Man{
        public synchronized void go(){
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("出去");
        }
        public synchronized void in(){
            System.out.println("进来");
        }
}

在这里插入图片描述
这里用两个Man对象,分别调用go和in方法,会先执行哪个?因为这里的锁锁的是对象,而他们不是同一个对象,所以资源不受影响。所以先执行in()

五锁

package com.onlyk.domexc.Seven8;

import java.util.concurrent.TimeUnit;

/**
 * @author only老K 我为自己代言
 * @create 2020-07-08 7:49
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class dome1 {
    public static void main(String[] args) {
        Man man=new Man();
        new Thread(()->{
            man.go();
        }).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            man.in();
        }).start();
    }
}
class Man{
        public static synchronized void go(){
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("出去");
        }
        public static synchronized void in(){
            System.out.println("进来");
        }
}

在这里插入图片描述
这里是通过一个对象,去调用静态的同步方法。这里锁的是Class对象(只有一个)。

六锁

package com.onlyk.domexc.Seven8;

import java.util.concurrent.TimeUnit;

/**
 * @author only老K 我为自己代言
 * @create 2020-07-08 7:49
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class dome1 {
    public static void main(String[] args) {
        Man man=new Man();
        Man king=new Man();
        new Thread(()->{
            man.go();
        }).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            king.in();
        }).start();
    }
}
class Man{
        public static synchronized void go(){
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("出去");
        }
        public static synchronized void in(){
            System.out.println("进来");
        }
}

这里是通过两个对象去调用go和in,结果是什么呢,答案还是先执行go,因为锁的是Class对象,所以不管是man还是king,都是属于Phone的Class对象。

七锁

package com.onlyk.domexc.Seven8;

import java.util.concurrent.TimeUnit;

/**
 * @author only老K 我为自己代言
 * @create 2020-07-08 7:49
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class dome1 {
    public static void main(String[] args) {
        Man man=new Man();
        new Thread(()->{
            man.go();
        }).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            man.in();
        }).start();
    }
}
class Man{
        public static synchronized void go(){
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("出去");
        }
        public synchronized void in(){
            System.out.println("进来");
        }
}

在这里插入图片描述
一个是静态同步方法,一个是普通同步方法,用一个对象对调用。静态同步方法锁的是Class对象,而普通同步方法锁的是调用者,锁的不是同一个东西。

八锁

package com.onlyk.domexc.Seven8;

import java.util.concurrent.TimeUnit;

/**
 * @author only老K 我为自己代言
 * @create 2020-07-08 7:49
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class dome1 {
    public static void main(String[] args) {
        Man man=new Man();
        Man king=new Man();
        new Thread(()->{
            man.go();
        }).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            king.in();
        }).start();
    }
}
class Man{
        public static synchronized void go(){
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("出去");
        }
        public synchronized void in(){
            System.out.println("进来");
        }
}

这里用两个对象去调用静态同步方法go和普通同步方法in,会先输出哪个,答案是in,因为go锁的是Class,而in锁的是调用者,不是同一个一个东西
在这里插入图片描述

线程池

package com.onlyk.domexc.Seven8;

import java.security.Policy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author only老K 我为自己代言
 * @create 2020-07-08 9:29
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class dome2 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(5);// 创建固定个数线程
//        ExecutorService pool1 = Executors.newCachedThreadPool();// 创建动态线程(自适应大小)
//        ExecutorService pool2 = Executors.newSingleThreadExecutor();// 创建单个线程
        pool.execute(new PoolThread());
        pool.execute(new PoolThread());
        pool.execute(new PoolThread());
        // 关闭连接 不关闭连接会一直占用CPU
        pool.shutdown();
    }
}
class PoolThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

在这里插入图片描述
但是按照阿里规范的话就是不推荐我们使用这种
在这里插入图片描述
对于ThreadPoolExecutor的学习,就从七大参数,四种拒绝策略
在这里插入图片描述

int corePoolSize// 核心线程池大小
int maximumPoolSize// 最大核心线程池大小
long keepAliveTime// 超时存活时间
TimeUnit unit//  超时单位
BlockingQueue<Runnable> workQueue// 阻塞队列
ThreadFactory threadFactory// 线程工厂,用于创建线程
RejectedExecutionHandler handler// 拒绝策略

四种拒绝策略:
AbortPolicy());// 银行满了还有人进来,不处理,抛出异常(默认)
CallerRunsPolicy();// 银行满了,不处理,哪里来的去哪里,一般抛给main线程
DiscardPolicy();// 银行满了,把该线程丢掉,不抛异常
DiscardOldestPolicy();// 银行满了,会和先来的线程竞争,不抛异常
package com.onlyk.domexc.Seven8;

import java.util.concurrent.*;

/**
 * @author only老K 我为自己代言
 * @create 2020-07-08 12:14
 * @blogaddress https://blog.csdn.net/weixin_44255950
 */
public class dome3 {
    public static void main(String[] args){
        /**
         * 用一个银行的例子进行讲解这七大参数
         */
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,// 两个常开营业窗口
                5,// 五个窗口,其中三个应急用
                3,// 超时存货时间
                TimeUnit.SECONDS,// 超时时间单位
                new LinkedBlockingDeque<>(3),// 银行候客区大小
                Executors.defaultThreadFactory(),// 默认线程池工厂
                new ThreadPoolExecutor.AbortPolicy());// 银行满了还有人进来,不处理,抛出异常(默认)
        // new ThreadPoolExecutor.CallerRunsPolicy();// 银行满了,不处理,哪里来的去哪里,一般抛给main线程
        // new ThreadPoolExecutor.DiscardPolicy();// 银行满了,把该线程丢掉,不抛异常
        // new ThreadPoolExecutor.DiscardOldestPolicy();// 银行满了,会和先来的线程竞争,不抛异常
        for (int i = 0; i < 8; i++) {
            threadPool.execute(()->{
                System.out.println(Thread.currentThread().getName());
            });
        }
        // 关闭连接
        threadPool.shutdown();
    }
}

end…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值