java(八) —— 线程安全与线程池问题

1.线程生命周期

1.新建
2.就绪
3.运行
4.阻塞
5.死亡

1.新建->就绪
start()方法

2.就绪->运行
获取cpu执行权

3.运行->就绪
失去cpu执行权
yield()方法

4.运行->阻塞
sleep(long time)
suspend() 已弃用
join()
等待同步锁
wait()

5.阻塞->运行
sleep结束
jion对应的线程结束
resume() 对应于suspend 已弃用
获取同步锁
notify() notifyAll()

6.运行->死亡
run()方法结束
stop()方法
出现error或者exception

2.线程安全解决方式一:同步代码块

sychronized(同步监视器,即锁){
//操作共享数据的代码
}

锁的要求:任意一个对象都可以充当锁,但是所有线程必须共用一个锁

package com.exer;

/**
 * @author ym
 * @create 2022-01-24 20:45
 * @description
 */
public class TicketDemo1 {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();

        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);
        Thread thread3 = new Thread(myThread);

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class MyThread implements Runnable {

    public int tickets = 100;

    public Object obj = new Object();

    /**
     * When an object implementing interface Runnable is used
     * to create a thread, starting the thread causes the object's
     * run method to be called in that separately executing
     * thread.
     * 

* The general contract of the method run is that it may * take any action whatsoever. * * @see Thread#run() */ @Override public void run() { while (true) { //此处加上了同步代码块 synchronized (obj) { if (tickets > 0) { System.out.println(Thread.currentThread().getName() + "\t" + tickets); tickets--; } else { break; } } } } }

package com.exer;

/**
 * @author ym
 * @create 2022-01-24 20:12
 * @description 三个窗口卖票问题
 */
public class TicketDemo {
    public static int tickets = 100;

    public static void main(String[] args) {
        TicketSell ticketSell1 = new TicketSell();
        TicketSell ticketSell2 = new TicketSell();
        TicketSell ticketSell3 = new TicketSell();

        ticketSell1.start();
        ticketSell2.start();
        ticketSell3.start();
    }
}

class TicketSell extends Thread {
    @Override
    public void run() {
        while (true) {
            synchronized (TicketSell.class) {
                if (TicketDemo.tickets > 0) {
                    TicketDemo.tickets--;
                    System.out.println(TicketDemo.tickets + "\t" + getName());
                } else {
                    break;
                }
            }
        }
    }
}

3.线程安全解决方式二:同步方法

如果某一方法全部涉及处理共享数据,则可将此方法设置为同步方法,但是需注意,实现runnable接口方法创建的线程与继承Thread方法在同步方法上略有不同
实现runnable()接口方法创建的线程可以直接同步,但是继承Thread()方法实现的线程在同步方法时需要设置为static,原理:
同步方法也是需要同步监视器的,只不过不需显式指明。如果是非static方法,则同步方法的同步监视器是对象,如果是static方法,则同步方法的同步监视器是类

package com.exer2;

/**
 * @author ym
 * @create 2022-01-24 20:12
 * @description 三个窗口卖票问题
 */
public class TicketDemo {
    public static int tickets = 100;

    public static void main(String[] args) {
        TicketSell ticketSell1 = new TicketSell();
        TicketSell ticketSell2 = new TicketSell();
        TicketSell ticketSell3 = new TicketSell();

        ticketSell1.start();
        ticketSell2.start();
        ticketSell3.start();
    }
}

class TicketSell extends Thread {
    @Override
    public void run() {
        while (true) {
            show();
        }
    }

    public static synchronized void show() {
        if (TicketDemo.tickets > 0) {
            TicketDemo.tickets--;
            System.out.println(TicketDemo.tickets + "\t" + Thread.currentThread().getName());
        }
    }
}

package com.exer2;

/**
 * @author ym
 * @create 2022-01-24 20:45
 * @description
 */
public class TicketDemo1 {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();

        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);
        Thread thread3 = new Thread(myThread);

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class MyThread implements Runnable {

    public int tickets = 100;

    public Object obj = new Object();

    /**
     * When an object implementing interface Runnable is used
     * to create a thread, starting the thread causes the object's
     * run method to be called in that separately executing
     * thread.
     * 

* The general contract of the method run is that it may * take any action whatsoever. * * @see Thread#run() */ @Override public void run() { while (true) { show(); } } public synchronized void show() { if (tickets > 0) { System.out.println(Thread.currentThread().getName() + "\t" + tickets); tickets--; } } }

4.手写一个线程安全的效率较高的懒汉式单例模式

/**
 * @author ym
 * @create 2022-01-25 11:10
 * @description 线程安全的效率较高的单例模式之懒汉式
 */
public class Sluggard {
    private Sluggard() {
    }

    public static Sluggard instanse = null;

    public Sluggard getInstanse() {
        if (instanse == null) {
            //如果是空,那么在下面同步代码块里进行操作,
            // 如果不是空,不需同步代码块,直接返回已经生成好了的实例即可
            synchronized (Sluggard.class) {
                instanse = new Sluggard();
            }
        }
        return instanse;
    }
}

5.线程的死锁问题

它的本质是由于同步机制引起的,不同的线程占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源
解决方法:
1.专门的算法、原则
2.尽量减少同步资源的定义
3.尽量避免嵌套同步

6.线程安全解决方式三:lock方法

此方法有个疑惑,写在前面,我在测试用继承Thread方法实现的线程时,并未实现同步效果,目前未想出原因,将代码也贴在下面

package com.lock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author ym
 * @create 2022-01-24 20:12
 * @description 三个窗口卖票问题
 */
public class TicketDemo {
    public static int tickets = 100;

    public static void main(String[] args) {
        TicketSell ticketSell1 = new TicketSell();
        TicketSell ticketSell2 = new TicketSell();
        TicketSell ticketSell3 = new TicketSell();

        ticketSell1.start();
        ticketSell2.start();
        ticketSell3.start();
    }
}

class TicketSell extends Thread {

    //1.获取ReentrantLock对象,如果参数为true,则每个线程的机会是公平的
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                //2.打开锁
                lock.lock();
                if (TicketDemo.tickets > 0) {
                    TicketDemo.tickets--;
                    System.out.println(TicketDemo.tickets + "\t" + Thread.currentThread().getName());
                } else {
                    break;
                }
            } finally {
                //3.关闭锁
                lock.unlock();
            }

        }
    }


}

package com.lock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author ym
 * @create 2022-01-24 20:45
 * @description
 */
public class TicketDemo1 {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();

        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);
        Thread thread3 = new Thread(myThread);

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class MyThread implements Runnable {

    public int tickets = 100;

//    public Object obj = new Object();

    public ReentrantLock lock = new ReentrantLock();

    /**
     * When an object implementing interface Runnable is used
     * to create a thread, starting the thread causes the object's
     * run method to be called in that separately executing
     * thread.
     * 

* The general contract of the method run is that it may * take any action whatsoever. * * @see Thread#run() */ @Override public void run() { while (true) { try { lock.lock(); if (tickets > 0) { System.out.println(Thread.currentThread().getName() + "\t" + tickets); tickets--; } else { break; } } finally { lock.unlock(); } } } // public synchronized void show() { // // } }

7.synchronized与lock的对比

1.lock是显式锁,需要手动开启和关闭锁,synchronized是隐式锁,出了作用域自动释放
2.lock只有代码块锁,synchronized有代码块锁和方法锁
3.lock锁可以使JVM更快地调度线程,性能更好

8.线程通信

常用:wait() notify() notifuAll()
注意:
1.这三个方法需要在同步方法或者同步代码块里调用
2.这三个方法的调用者是同步监视器
3.这三个方法定义在Object类中

9.wait() 与 sleep()的不同

1.两个方法的声明位置不同,一个在Object类,一个在Thread类
2.两个方法的调用要求不同,wait()只能在同步代码块或者同步方法调用,sleep()可以在任何场景调用
3.sleep()不会释放同步监视器,wait()会

10.消费者生产者问题

package com.produce_and_consume;

/**
 * @author ym
 * @create 2022-01-25 17:59
 * @description 生产者消费者模型,店员随时判断,如果超过20个货物,让生产者暂停,如果少于0个货物,让生产者工作,消费者暂停
 */
public class ClerkTest {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Producer producer = new Producer(clerk);
        Thread produce = new Thread(producer);
        produce.start();


        Consumer consumer = new Consumer(clerk);
        Thread consume = new Thread(consumer);
        consume.start();
    }
}


class Clerk {
    //货物  初始数量为0
    public int goods = 0;

    /**
     * 生产者进行生产,需注意:
     * 1.如果生产超过1个货物,就开始提醒消费者开始消费
     * 2.如果少于20个货物,就开始生产
     * 3.如果多于20个货物,就暂停生产
     */
    public synchronized void produce() {

        if (goods < 20) {
            goods++;
            System.out.println(Thread.currentThread().getName() + "开始生产第" + goods + "个商品");
            notify();
        } else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


    }

    /**
     * 消费者进行消费,需注意:
     * 1.如果消费超过1个货物,就开始提醒生产者进行生产
     * 2.如果多于1个货物,就开始消费
     * 3.如果少于1个货物,就暂停消费
     */
    public synchronized void consume() {

        if (goods > 0) {
            System.out.println(Thread.currentThread().getName() + "开始消费第" + goods + "个货物");
            goods--;
            notify();
        } else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

class Producer implements Runnable {

    private Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    /**
     * When an object implementing interface Runnable is used
     * to create a thread, starting the thread causes the object's
     * run method to be called in that separately executing
     * thread.
     * 

* The general contract of the method run is that it may * take any action whatsoever. * * @see Thread#run() */ @Override public void run() { System.out.println("生产者开始生产产品"); while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } clerk.produce(); } } } class Consumer implements Runnable { private Clerk clerk; public Consumer(Clerk clerk) { this.clerk = clerk; } /** * When an object implementing interface Runnable is used * to create a thread, starting the thread causes the object's * run method to be called in that separately executing * thread. *

* The general contract of the method run is that it may * take any action whatsoever. * * @see Thread#run() */ @Override public void run() { System.out.println("消费者开始消费产品"); while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } clerk.consume(); } } }

11.创建线程方式三:实现callable()接口

package com.callable;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @author ym
 * @create 2022-01-25 19:31
 * @description 使用callable方法创建线程  目的是打印100以内所有偶数的和
 */
public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThreadTest threadTest = new ThreadTest();

        FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(threadTest);

        Thread thread = new Thread(integerFutureTask);

        thread.start();

        Integer integer = integerFutureTask.get();
        System.out.println(integer);
    }
}

class ThreadTest implements Callable {

    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if (i % 2 == 0) {
                sum += i;
            }
        }
        return sum;
    }
}

12.使用线程池

package com.ThreadPool;

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

/**
 * @author ym
 * @create 2022-01-25 19:54
 * @description
 */
public class ThreadPool {
    public static void main(String[] args) {
        //1.创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        //4.设置线程池属性
        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;
        threadPoolExecutor.setCorePoolSize(15);

        //2.使用线程池
        executorService.execute(new Thread1());
        executorService.submit(new Thread2());

        //3.关闭线程池
        executorService.shutdown();


    }
}

class Thread1 implements Runnable {

    /**
     * When an object implementing interface Runnable is used
     * to create a thread, starting the thread causes the object's
     * run method to be called in that separately executing
     * thread.
     * 

* The general contract of the method run is that it may * take any action whatsoever. * * @see Thread#run() */ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); } } } class Thread2 implements Callable { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ @Override public Object call() throws Exception { for (int i = 10; i < 20; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); } return null; } }

你可能感兴趣的:(Java,java,安全,开发语言)