【JAVA】多线程编程实现实例(全面实现)

首先,我们我们要进行多线程编程,最少线程怎么创建时最基本的知识。

创建线程由四种方式

1.继承Thread类创建线程(重写run方法,用start()开启线程)

2.实现Runable接口创建线程(重写run方法,也是start来开启线程)

3.使用Callable和Future创建线程(用Lambda表达式创建Callable<Integer>对象,用Future来包装该对象,可以有返回值)

4.使用线程池(Executore框架)

我们创建一个场景,有三个站台再卖20张票,再一个站台卖某张票的时候,其他站台不能同时卖这张票。

线程创建方式知道了,那么多线程编程还有一个很重要的就是怎么同步

1.synchronized关键字

2.Atomic实现原子性

3.lock锁

1、继承Thread类创建线程

synchronized关键字

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

public class TestThread2 {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        Station1 st1 = new Station1("station 1",countDownLatch);
        Station1 st2 = new Station1("station 2",countDownLatch);
        Station1 st3 = new Station1("station 3",countDownLatch);
        long time = System.currentTimeMillis();
        st1.start();
        st2.start();
        st3.start();
        countDownLatch.await();
        System.out.println((System.currentTimeMillis() - time));

    }
}
class Station1 extends Thread {
    static CountDownLatch countDownLatch;
    Object lock  = "lock";
    static int tick = 20;//保持多个站台线程间票量一直要用static
    public Station1(String name, CountDownLatch countDownLatch){
        super(name);//给线程命名
        this.countDownLatch = countDownLatch;
    }


    @Override
    public void run(){
        while(tick > 0){
            synchronized (lock){
                if(tick > 0){
                    System.out.println(getName() + " 卖出了第" + tick  + "张票" );
                    tick--;
                    //System.out.println("剩下 " + tick + " 张票" );
                }else {
                    System.out.println("票卖完了");
                }
                try {
                    sleep(1000);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
        countDownLatch.countDown();
    }
}

输出结果,可以看到卖20张票因为synchronized锁的缘故,时间非常慢,要用20多秒,synchronized的效率问题已经很直观了。

Atomic实现原子性

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

public class TestThread {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        Station st1 = new Station("station 1",countDownLatch);
        Station st2 = new Station("station 2",countDownLatch);
        Station st3 = new Station("station 3",countDownLatch);
        long time = System.currentTimeMillis();
        st1.start();
        st2.start();
        st3.start();
        countDownLatch.await();
        System.out.println((System.currentTimeMillis() - time));

    }
}
class Station extends Thread {
    static CountDownLatch countDownLatch;
    static AtomicInteger tick = new AtomicInteger(20);//保持多个站台线程间票量一直要用static
    public Station(String name, CountDownLatch countDownLatch){
        super(name);//给线程命名
        this.countDownLatch = countDownLatch;
    }


    @Override
    public void run(){
        while(tick.get() > 0){
            if(tick.get() > 0){
                int i = tick.getAndDecrement();
                System.out.println(getName() + " 卖出了第" + i  + "张票" );
                //System.out.println("剩下 " + tick + " 张票" );
            }else {
                System.out.println("票卖完了");
            }
            try {
                sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        countDownLatch.countDown();
    }
}

lock锁

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestThread3 {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        Station st1 = new Station("station 1",countDownLatch);
        Station st2 = new Station("station 2",countDownLatch);
        Station st3 = new Station("station 3",countDownLatch);
        long time = System.currentTimeMillis();
        st1.start();
        st2.start();
        st3.start();
        countDownLatch.await();
        System.out.println((System.currentTimeMillis() - time));

    }
}
class Station3 extends Thread {
    static CountDownLatch countDownLatch;
    static int tick = 20;//保持多个站台线程间票量一直要用static
    private Lock lock = new ReentrantLock();
    public Station3(String name, CountDownLatch countDownLatch){
        super(name);//给线程命名
        this.countDownLatch = countDownLatch;
    }


    @Override
    public void run(){

        while(tick > 0){
            lock.lock();
            if(tick > 0){
                System.out.println(getName() + " 卖出了第" + tick  + "张票" );
                tick --;
                //System.out.println("剩下 " + tick + " 张票" );
            }else {
                System.out.println("票卖完了");
            }
            lock.unlock();
            try {
                sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        countDownLatch.countDown();
    }
}

结果

可以看到,Atomic和lock的时间差不多,因为底层实现都是CAS,所以比synchronized要快很多,AtomicInteger用起来比较方便,所以后面的例子值用AtomicInteger来实现。

2、实现Runable接口创建线程

可以看到,第一个不同是实现了Runnable接口的Station类并不是一个Thread对象,所以在start的时候需要new一个Thread对象然后执行,这一步,没有Thread方便。

第二个是给线程命名需要自己手动写,所以也麻烦了不少。

Runnable接口的好处就是实现了Runnable接口还可以实现别的接口,但是继承了Thread类就只能继承这一个类了,所以可以根据情况进行选择。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

import static java.lang.Thread.sleep;

public class TestThread {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        Station st1 = new Station("station 1",countDownLatch);
        Station st2 = new Station("station 2",countDownLatch);
        Station st3 = new Station("station 3",countDownLatch);
        long time = System.currentTimeMillis();
        new Thread(st1).start();
        new Thread(st2).start();
        new Thread(st3).start();
        countDownLatch.await();
        System.out.println((System.currentTimeMillis() - time));

    }
}
class Station implements Runnable {
    static CountDownLatch countDownLatch;
    static AtomicInteger tick = new AtomicInteger(20);//保持多个站台线程间票量一直要用static
    String name;
    public Station(String name, CountDownLatch countDownLatch){
        this.name = name;//给线程命名
        this.countDownLatch = countDownLatch;
    }

    public String getName() {
        return name;
    }

    @Override
    public void run(){
        while(tick.get() > 0){
            if(tick.get() > 0){
                int i = tick.getAndDecrement();
                System.out.println(getName() + " 卖出了第" + i  + "张票" );
                //System.out.println("剩下 " + tick + " 张票" );
            }else {
                System.out.println("票卖完了");
            }
            try {
                sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        countDownLatch.countDown();
    }
}

3、使用Callable和Future创建线程

在JDK8出来后,使用Callable和Future创建线程可以用Lambda表达式来创建线程

import java.awt.*;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicInteger;

import static java.lang.Thread.sleep;

public class TestThread {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        long time = System.currentTimeMillis();

        AtomicInteger tick = new AtomicInteger(20);
        for(int i  = 0; i < 3 ;++ i){
            FutureTask<Integer> station = new FutureTask<>((Callable<Integer>)()->{
                while(tick.get() > 0){
                    if(tick.get() > 0){
                        int j = tick.getAndDecrement();
                        System.out.println(Thread.currentThread().getName() + " 卖出了第" + j  + "张票" );
                        //System.out.println("剩下 " + tick + " 张票" );
                    }else {
                        System.out.println("票卖完了");
                    }
                    try {
                        sleep(1000);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
                countDownLatch.countDown();
                return tick.get();
            });
            new Thread(station, "station" + i).start();
        }
        countDownLatch.await();
        System.out.println((System.currentTimeMillis() - time));

    }
}

结果

4、使用线程池(Executore框架)

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static java.lang.Thread.sleep;

public class TestThread3 {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        ExecutorService executorService = Executors.newCachedThreadPool();
        long time = System.currentTimeMillis();
        for (int i = 0; i < 3; ++i){
            String name = "station" + i;
            executorService.execute(new Station(name,countDownLatch));
        }
        countDownLatch.await();
        System.out.println((System.currentTimeMillis() - time));

        executorService.shutdown();
    }
}
class Station implements Runnable {
    static CountDownLatch countDownLatch;
    static AtomicInteger tick = new AtomicInteger(20);//保持多个站台线程间票量一直要用static
    private final String name;

    public Station(String name, CountDownLatch countDownLatch){
        this.name = name;//给线程命名
        this.countDownLatch = countDownLatch;
    }

    public String getName() {
        return name;
    }

    @Override
    public void run(){
        while(tick.get() > 0){
            if(tick.get() > 0){
                System.out.println(getName() + " 卖出了第" + tick.getAndDecrement() + "张票" );
                //System.out.println("剩下 " + tick + " 张票" );
            }else {
                System.out.println("票卖完了");
            }
            try {
                sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }

        }
        countDownLatch.countDown();
    }
}

结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值