java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java线程同步机制

Java三大线程同步机制代码实战指南

作者:程序员码小跳

文章介绍了Java线程的五种状态(新建、就绪、运行、阻塞、死亡),以及线程的创建方式(继承Thread类、实现Runnable接口、实现Callable接口),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

线程状态

创建线程

继承Thread类[无入参、无返回值]

实现步骤:

1.创建一个Thread类的子类 class MyThread extends Thread
2.在Thread类的子类中重写Thread类中的run()方法
3.创建Thread类的子类对象 MyThread t1 = new MyThread();
4.调用Thread类中的方法start()方法,开启新的线程,执行run方法 t1.start()
class MyThread extends Thread {
    @Override
    public void run() {
    }
}
public class demo21Thread01 {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
    }
}

实现Runnable接口[无入参,无返回值]

实现步骤:

1.创建一个Runnable接口的实现类 class myThread implements Runnable

2.在实现类中重写Runnable接口的run方法

3.创建一个Runnable接口的实现类对象 myThread t1 = new myThread();

4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象Thread t=new Thread(t1);

5.调用Thread类中的start方法,开启新的线程执行run方法 t.start()

class myThread02 implements Runnable {
    public void run() {
    }
}
public class demo21Thread01 {
    public static void main(String args[]) throws InterruptedException {
        myThread02 mythread = new myThread02();
        Thread t = new Thread(mythread);
        t.start();
    }
}

实现Callable接口[无入参,有返回值]

class MyTask implements Callable<String> {
    @Override
    public String call() throws Exception {
        try {
            // 模拟业务处理
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "success";
    }
}
public class demo21Thread01 {
    public static void main(String[] args) throws Exception {
        // 1、callable怎么用,引入FutureTask初始化
        FutureTask<String> futureTask = new FutureTask<>(new MyTask());
        new Thread(futureTask).start();
        // 2、FutureTask线程启动,与main线程互不干扰
        while (!futureTask.isDone()) {
        }
        // 3、获得返回值:get方法尽量放在后面,一旦调用,线程等待等到执行完毕,会导致堵塞
        String value = futureTask.get();
        System.out.println("MyData的返回值:" + value);
    }
}

通过线程池方式

ExecutorService es= Executors.newCachedThreadPool();		//缓存型线程池
ExecutorService es= Executors.newFixedThreadPool(2);		//固定型线程池
ExecutorService es=Executors.newSingleThreadExecutor();  	//单线程型线程池
以上三种通过es.submit(new MyRunable03(i));提交任务
ScheduledExecutorService es = Executors.newScheduledThreadPool(3);//延迟执行或重复执行型线程池
通过es.schedule(new myRunnable(i), 2, TimeUnit.SECONDS);提交任务

通过lambda表达式

new Thread(() -> {
    System.out.println("程序已启动");
}).start();

线程同步

3种让线程等待和唤醒的方法

方式1: Object中的wait()线程等待、notify()唤醒线程【PS:必须配合synchronized】

方式2: Condition的await()线程等待、signal()唤醒线程【PS:必须配合ReentrantLock】

方式3: LockSupport的park()线程等待、unpark()唤醒线程

package thread;
/*
 * 两个线依次次输出1 2 3 4
 */
public class ThreadSyncTest2 {
    // 使用专用锁对象(不可变)
    private static Object LOCK = new Object();
    private static int num = 1;
    public static void main(String[] args) {
        new Thread(() -> {
            while (num <= 10) {
                try {
                    synchronized (LOCK) {
                        if (num % 2 == 0) {
                            System.out.println("偶数线程A: " + num++);
                            LOCK.notify();
                        } else {
                            LOCK.wait();
                        }
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }, "偶数线程A").start();
        new Thread(() -> {
            while (num <= 10) {
                try {
                    synchronized (LOCK) {
                        if (num % 2 == 1) {
                            System.out.println("基数线程B: " + num++);
                            LOCK.notify();
                        } else {
                            LOCK.wait();
                        }
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }, "基数线程B").start();
    }
}
package thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/*
 * 两个线程一次输出1 2 3 4
 */
public class ThreadSyncTest3 {
    private static int num = 1;
    // 锁与条件变量
    private static final ReentrantLock LOCK = new ReentrantLock();
    private static final Condition ODD_COND = LOCK.newCondition();    // 奇数条件队列
    private static final Condition EVEN_COND = LOCK.newCondition();    // 偶数条件队列
    public static void main(String[] args) {
        new Thread(() -> {
            while (num <= 10) {
                LOCK.lock();
                try {
                    if (num % 2 == 0) {
                        System.out.println("偶数线程A: " + num++);
                        ODD_COND.signal();
                    } else {
                        EVEN_COND.await();
                    }
                } catch (InterruptedException e) {
                    break;
                } finally {
                    LOCK.unlock();
                }
            }
            EVEN_COND.signal();
        }, "偶数线程A").start();
        new Thread(() -> {
            while (num <= 10) {
                LOCK.lock();
                try {
                    if (num % 2 == 1) {
                        System.out.println("基数线程B: " + num++);
                        EVEN_COND.signal();
                    } else {
                        ODD_COND.await();
                    }
                } catch (InterruptedException e) {
                    break;
                } finally {
                    LOCK.unlock();
                }
            }
            EVEN_COND.signal();
        }, "基数线程B").start();
    }
}

方式1和方式2存在的问题

1、线程先要获得并持有锁,必须在锁块(synchronized或lock)中,必须配合使用

2、必须要先等待后唤醒,线程才能够被唤醒

LockSupport主要是解决上面2个问题,LockSupport 类使用了一种名为 permit(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit),permit 只有两个值 1 和零,默认是零,不能累积

到此这篇关于Java三大线程同步机制代码实战指南的文章就介绍到这了,更多相关java线程同步机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文