博客
关于我
java多线程
阅读量:618 次
发布时间:2019-03-12

本文共 8578 字,大约阅读时间需要 28 分钟。

多线程详解

1 线程简介

程序是指令和数据的有序集合,是静态的概念;进程是程序的一次执行过程,是一个动态的概念,是系统资源分配的单位;线程是CPU调度和执行的单位。

注意:很多多线程是模拟出来的,真正的多线程是指有多个CPU,即多核。

在程序运行时,即使自己没有创建线程,后台也会有多个线程,如主线程、gc线程。

对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制。

2 线程创建

2.1 继承Thread类

为了创建线程,可以通过继承Thread类并实现run()方法。以下是一个实现的示例:

public class TestThread2 extends Thread {    private String url;    private String name;    public TestThread2(String url, String name) {        this.url = url;        this.name = name;    }    @Override    public void run() {        WebDownloader downloader = new WebDownloader();        downloader.download(url, name);        System.out.println("下载了文件名为:" + name);    }    public static void main(String[] args) {        TestThread2 t1 = new TestThread2("https://pics7.baidu.com/feed/0d338744ebf81a4cbf5a41d981e0105e242da68c.jpeg?token=760f959b12c1adc6be805c125a569b6b", "1.jpg");        TestThread2 t2 = new TestThread2("https://pics3.baidu.com/feed/9358d109b3de9c8231a97ed1ca4fef0d1bd843f2.jpeg?token=766bf62b302cb0d56fb24c4469bb57a2", "2.jpg");        TestThread2 t3 = new TestThread2("https://pics3.baidu.com/feed/314e251f95cad1c8773c1c6ddaf0080ecb3d51cf.jpeg?token=42e2511b4151fcf2d648be6eff246e1d", "3.jpg");        t1.start();        t2.start();        t3.start();    }}

2.2 实现Runnable接口

线程可以通过实现Runnable接口来创建。Runnable接口提供一个run()方法,线程实现该方法即可。以下是一个实现的示例:

public class TestThread3 implements Runnable {    public void run() {        for (int i = 0; i < 10; i++) {            System.out.println("我在看第-" + i + "-行代码");        }    }    public static void main(String[] args) {        TestThread3 testThread3 = new TestThread3();        new Thread(testThread3).start();    }}

注意:Thread类实现了Runnable接口,因此可以用Thread类的方式创建线程。

2.3 小结

创建线程的核心方法有两种方式:继承Thread类和实现Runnable接口。无论使用哪种方式,线程的创建和运行流程是相同的。

3 线程方法

3.1 线程停止

线程的停止通常可以通过 호출stop()方法实现,但stop()方法可能导致线程中断当前的休眠状态。此外,也可以通过标志控制线程的执行状态。

public class TestStop implements Runnable {    private boolean flag = true;    public void run() {        while (flag) {            System.out.println("run...Thread");        }    }    public void stop() {        this.flag = false;    }    public static void main(String[] args) {        TestStop task = new TestStop();        new Thread(task).start();    }}

3.2 线程休眠

线程的休眠可以通过调用sleep()方法实现,sleep()方法会让线程暂停执行。但sleep()方法不会释放同步锁。

public class TestSleep implements Runnable {    public void run() {        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        TestSleep task = new TestSleep();        new Thread(task).start();    }}

3.3 线程礼让

线程可以通过调用yield()方法进行礼让,使当前线程暂时离开CPU,从而给其他线程让行。

public class TestYield implements Runnable {    public void run() {        while (true) {            System.out.println("running... Thread");            Thread.yield();        }    }    public static void main(String[] args) {        TestYield task = new TestYield();        new Thread(task).start();        new Thread(task).start();    }}

3.4 线程合并

线程可以通过调度器(Scheduler)来实现合并或者插队。在Java中,可以使用ExecutorService来管理线程池。

4 线程同步

4.1 线程不安全

并行访问共享资源时,如果没有采取同步措施,可能会导致数据竞争和纷乱。如下面的例子使用了一个非线程安全的集合:

public class UnsafeList {    public static void main(String[] args) {        ArrayList list = new ArrayList();        for (int i = 0; i < 1000; i++) {            new Thread(() -> {                list.add(Thread.currentThread().getName());            }).start();        }        System.out.println(list.size());    }}

4.2 同步方法

通过使用synchronized关键字可以实现方法同步。以下是一个线程安全的集合操作示例:

public class SafeList {    public static void main(String[] args) {        ArrayList list = new ArrayList();        for (int i = 0; i < 1000; i++) {            new Thread(() -> {                synchronized (list) {                    list.add(Thread.currentThread().getName());                }            }).start();        }        try {            Thread.sleep(3000);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(list.size());    }}

4.3 同步代码块

代码块中的synchronized可以实现对特定对象的锁定。以下是一个线程安全的集合操作示例:

public class SafeList {    public static void main(String[] args) {        ArrayList list = new ArrayList();        for (int i = 0; i < 1000; i++) {            new Thread(() -> {                synchronized (list) {                    list.add(Thread.currentThread().getName());                }            }).start();        }        try {            Thread.sleep(3000);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(list.size());    }}

4.4 死锁

死锁是多个线程同时阻塞,无法继续执行的状态。避免死锁的关键是及时释放锁。以下是一个可能导致死锁的示例:

public class DeadLock {    // 假设选择和lipstick和mirror    private int choice = 100;    private String lipstick;    private String mirror;    public void make() throws InterruptedException {        if (choice == 0) {            synchronized (lipstick) {                System.out.println(this.girlName + "获得了口红");                Thread.sleep(1000);                synchronized (mirror) {                    System.out.println(this.girlName + "获得了镜子");                }            }        } else {            synchronized (mirror) {                System.out.println(this.girlName + "获得了镜子");                Thread.sleep(1000);                synchronized (lipstick) {                    System.out.println(this.girlName + "获得了口红");                }            }        }    }}

4.5 Lock

Lock是一种显式的锁机制,可以提供更细粒度的同步控制。以下是一个Lock的示例:

public class TestLock implements Runnable {    private final ReentrantLock lock = new ReentrantLock();    private Integer ticketNum = 10;    public void run() {        while (true) {            if (ticketNum <= 0) {                break;            }            lock.lock();            try {                System.out.println(Thread.currentThread().getName() + "拿到了第" + ticketNum-- + "张票");                Thread.sleep(200);            } catch (InterruptedException e) {                e.printStackTrace();            } finally {                lock.unlock();            }        }    }    public static void main(String[] args) {        TestLock ticket = new TestLock();        new Thread(ticket, "小明").start();        new Thread(ticket, "小红").start();        new Thread(ticket, "黄牛党").start();    }}

4.6 线程协作

5.6.1 生产者消费者问题

生产者消费者问题是一个经典的线程协作问题。以下是一个使用管程法的解决方案:

public class SynContainer {    Chicken[] chickens = new Chicken[10];    private int count = 0;    public synchronized void push(Chicken chicken) {        if (count == chickens.length) {            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        chickens[count] = chicken;        count++;        this.notifyAll();    }    public synchronized Chicken pop() {        if (count == 0) {            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        count--;        this.notifyAll();        return chickens[count];    }}

5.6.2 线程通信

线程通信是线程协作的重要部分。以下是一个线程通信的示例:

public class CommExample {    private Integer result = 0;    private boolean flag = false;    public void produce() {        if (!flag) {            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        result = 101;        this.notifyAll();        this.flag = !this.flag;    }    public void consume() {        if (flag) {            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        System.out.println("Consumer consumed: " + result);        this.notifyAll();        this.flag = !this.flag;    }    public static void main(String[] args) {        CommExample ce = new CommExample();        Runnable producer = () -> ce.produce();        Runnable consumer = () -> ce.consume();        new Thread(producer).start();        new Thread(consumer).start();    }}

5 线程池

5.1 线程池优点

线程池可以有效管理线程资源,提供更高效的资源利用率和更好的线程管理。

5.2 使用线程池

public class TestPool {    public static void main(String[] args) {        ExecutorService service = Executors.newFixedThreadPool(10);        service.execute(new MyTask());        service.execute(new MyTask());        service.shutdown();    }    public static class MyTask implements Runnable {        @Override        public void run() {            for (int i = 0; i < 5; i++) {                System.out.println(Thread.currentThread().getName() + "正在运行...");            }        }    }}

通过线程池可以简化线程管理代码,提高线程复用率,避免资源浪费。

转载地址:http://tiwaz.baihongyu.com/

你可能感兴趣的文章
No module named ‘MySQLdb‘错误解决No module named ‘MySQLdb‘错误解决
查看>>
No new migrations found. Your system is up-to-date.
查看>>
No qualifying bean of type XXX found for dependency XXX.
查看>>
No resource identifier found for attribute 'srcCompat' in package的解决办法
查看>>
no session found for current thread
查看>>
No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android
查看>>
NO.23 ZenTaoPHP目录结构
查看>>
no1
查看>>
NO32 网络层次及OSI7层模型--TCP三次握手四次断开--子网划分
查看>>
NoClassDefFoundError: org/springframework/boot/context/properties/ConfigurationBeanFactoryMetadata
查看>>
Node JS: < 一> 初识Node JS
查看>>
Node Sass does not yet support your current environment: Windows 64-bit with Unsupported runtime(72)
查看>>
Node-RED中使用JSON数据建立web网站
查看>>
Node-RED中使用json节点解析JSON数据
查看>>
Node-RED中使用node-random节点来实现随机数在折线图中显示
查看>>
Node-RED中使用node-red-browser-utils节点实现选择Windows操作系统中的文件并实现图片预览
查看>>
Node-RED中使用node-red-contrib-image-output节点实现图片预览
查看>>
Node-RED中使用node-red-node-ui-iframe节点实现内嵌iframe访问其他网站的效果
查看>>
Node-RED中使用Notification元件显示警告讯息框(温度过高提示)
查看>>
Node-RED中实现HTML表单提交和获取提交的内容
查看>>