栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java 线程相关

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java 线程相关

目录

线程的实现方式

方式一:继承Thread

方式二:实现接口Runnable

方式三:实现接口Callable

测试

线程终止

线程暂停Sleep()

线程礼让yield

进程插队Join

进程状态

进程优先级

守护线程setDaemon

线程不安全:三大案例

线程同步(同步块/同步方法)synchronized

synchronized同步方法

synchronized同步块

线程性能分析

典例


线程的实现方式

方式一:继承Thread

        继承Thread的方式不推荐使用,因为开发过程很多时候需要继承其他的类,因而会导致无法继承其他的类。所以使用一下两种方式。

package thread;

import lombok.AllArgsConstructor;


@AllArgsConstructor
public class ThreadManner1 extends Thread {

    private String url;
    private String fileName;

    @Override
    public void run() {
        WebDownload wd = new WebDownload();
        wd.download(url, fileName);
        System.out.println(fileName);
    }

}

方式二:实现接口Runnable
package thread;

import lombok.AllArgsConstructor;


@AllArgsConstructor
public class ThreadManner2 implements Runnable {

    private String url;
    private String fileName;

    @Override
    public void run() {
        WebDownload wd = new WebDownload();
        wd.download(url, fileName);
        System.out.println(fileName);
    }
}

方式三:实现接口Callable
package thread;

import lombok.AllArgsConstructor;

import java.util.concurrent.Callable;


@AllArgsConstructor
public class ThreadManner3 implements Callable {

    private String url;
    private String fileName;

    @Override
    public Object call() throws Exception {
        WebDownload wd = new WebDownload();
        wd.download(url, fileName);
        System.out.println(fileName);
        return true;
    }
}

测试
package thread;

import lombok.Getter;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


@Getter
public class WebDownload {

    public void download(String url, String fileName) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(fileName));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        String url1 = "https://cdn.luogu.com.cn/fe/logo.png?0fdd294ff62e331d2f70e1a37ba4ee02";
        String url2 = "https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b?ver=5c31";
        String url3 = "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png";
        String fileName1 = "luogu.png";
        String fileName2 = "microsoft.png";
        String fileName3 = "baidu.png";

        //方式一
//        ThreadManner1 tm1 = new ThreadManner1(url1, fileName1);
//        ThreadManner1 tm2 = new ThreadManner1(url2, fileName2);
//        ThreadManner1 tm3 = new ThreadManner1(url3, fileName3);
//        tm1.start();
//        tm2.start();
//        tm3.start();

//        //方式二
//        ThreadManner2 tm1 = new ThreadManner2(url1, fileName1);
//        ThreadManner2 tm2 = new ThreadManner2(url2, fileName2);
//        ThreadManner2 tm3 = new ThreadManner2(url3, fileName3);
//        Thread t1 = new Thread(tm1);
//        Thread t2 = new Thread(tm2);
//        Thread t3 = new Thread(tm3);
//        t1.start();
//        t2.start();
//        t3.start();

        //方式三
        //1. 创建目标对象:
        ThreadManner3 tm1 = new ThreadManner3(url1, fileName1);
        ThreadManner3 tm2 = new ThreadManner3(url2, fileName2);
        ThreadManner3 tm3 = new ThreadManner3(url3, fileName3);
        //2. 创建执行服务:
        ExecutorService ser = Executors.newFixedThreadPool(3);
        //3. 提交执行:
        Future result1 = ser.submit(tm1);
        Future result2 = ser.submit(tm2);
        Future result3 = ser.submit(tm3);
        //4. 获取结果:
        boolean r1 = result1.get();
        boolean r2 = result2.get();
        boolean r3 = result3.get();
        //5. 关闭服务:
        ser.shutdownNow();
    }
}

线程终止

线程的终止,直接使用stop()是不安全的,所以这里在线程中加入标识,根据标识来终止线程。

package thread;


public class ThreadStop implements Runnable {

    private boolean flag = true;
    private String name;

    public ThreadStop(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println(name + "-->" + i++);
        }
    }

    public void stop() {
        this.flag = false;
    }

    public static void main(String[] args) {
        ThreadStop ts = new ThreadStop("wwk");
        new Thread(ts).start();

        for (int i = 0; i < 2000; i++) {
            if (i == 1880) {
                ts.stop();
                System.out.println("ts------------>stop");
            }
            System.out.println("main-->" + i);
        }
    }
}

线程暂停Sleep()
package thread;


public class ThreadSleepTest {

    public static void main(String[] args) {
        BuyTickets bt = new BuyTickets();

        //打印当前线程的名字
        System.out.println(Thread.currentThread().getName());

        //模拟多人买票
        new Thread(bt, "wwk1").start();
        new Thread(bt, "wwk2").start();
        new Thread(bt, "wwk3").start();
    }

}


class BuyTickets implements Runnable {
    private int ticketNums = 100;

    @Override
    public void run() {
        while (true) {
            if (ticketNums <= 0) {
                break;
            }
            //模拟线程暂停,占用资源暂停200ms
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->" + ticketNums--);
        }
    }
}

线程礼让yield

        礼让是将进程重新放回就绪状态,等待CPU的分配,而不是进入阻塞状态。

package thread;


public class ThreadYieldTest {

    public static void main(String[] args) {
        TestYield ty = new TestYield();
        new Thread(ty, "wwk1").start();
        new Thread(ty, "wwkw").start();
    }

}

class TestYield implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "-->" + "start");
        Thread.yield();
        System.out.println(Thread.currentThread().getName() + "-->" + "end");
    }
}

进程插队Join

        除了插队的进程外都加上join方法。

package thread;


public class ThreadJoinTest1 {

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                System.out.println("Thread..." + i);
            }
        });
        t.start();

        for (int i = 0; i < 100; i++) {
            if (i == 20) {
                t.join();
            }
            System.out.println("main..." + i);
        }
    }
}

进程状态

NEW:尚未启动的线程处于此状态。 
RUNNABLE:在Java虚拟机中执行的线程处于此状态。 
BLOCKED:被阻塞等待监视器锁定的线程处于此状态。 
WAITING:无限期等待另一个线程执行特定操作的线程处于此状态。 
TIMED_WAITING:正在等待另一个线程执行最多指定等待时间的操作的线程处于此状态。 
TERMINATED:已退出的线程处于此状态。

package thread;

import java.lang.Thread.State;


public class ThreadStateTest {

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            for (int i = 0; i < 15; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("......" + i);
            }
        });


        //查看当前进程的状态
        State state = t.getState();
        //NEW新生状态
        System.out.println(state);

        t.start();
        state = t.getState();
        //RUNNABLE正在运行的状态
        System.out.println(state);

        while (state != State.TERMINATED) {
            Thread.sleep(1000);
            state = t.getState();
            System.out.println(state);
        }
        state = t.getState();
        //TERMINATED结束
        System.out.println(state);

        while (true) {
            //目前的线程数
            int num = Thread.activeCount();
            if (num == 1) {
                break;
            }
            Thread.sleep(200);
            state = Thread.currentThread().getState();
            //RUNNABLE运行态
            System.out.println(state);
        }
    }
}

进程优先级
package thread;


public class ThreadPriorityTest {

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority());

        MyPriority mp = new MyPriority();

        Thread t1 = new Thread(mp, "t1");
        Thread t2 = new Thread(mp, "t2");
        Thread t3 = new Thread(mp, "t3");
        Thread t4 = new Thread(mp, "t4");
        Thread t5 = new Thread(mp, "t5");

        t1.setPriority(10);
        t2.setPriority(Thread.MIN_PRIORITY);
        t3.setPriority(Thread.MIN_PRIORITY);
        t4.setPriority(Thread.MAX_PRIORITY);
        t5.setPriority(Thread.MAX_PRIORITY);

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        
    }
}

class MyPriority implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority());
    }
}

守护线程setDaemon

        守护进程,若在其他进程完成之前执行结束,就结束;若其他进程都结束了,则守护进程也随之结束(无论守护进程是否执行完)。

package thread;


public class ThreadDaemonTest {

    public static void main(String[] args) {
        Teacher tea = new Teacher();
        Student stu = new Student();
        Runnable target;
        Thread t = new Thread(tea);
        t.setDaemon(true);
        t.start();
        new Thread(stu).start();
    }
}

class Student implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 365 * 4; i++) {
            System.out.println("上学。。。");
        }
        System.out.println("毕业。。。");
    }
}

class Teacher implements Runnable {

    @Override
    public void run() {
        while (true) {
            System.out.println("上班。。。(永不退休)");
        }
    }
}

线程不安全:三大案例

抢票:可能会出现负数或相同的数

package thread;


public class UnSafeThreadTest {

    public static void main(String[] args) {
        Tickets t = new Tickets();
        Thread t1 = new Thread(t, "wwk1");
        Thread t2 = new Thread(t, "wwk2");
        Thread t3 = new Thread(t, "wwk3");
        t1.start();
        t2.start();
        t3.start();
    }
}

class Tickets implements Runnable {

    private int ticketNums = 100;

    @Override
    public void run() {
        while (true) {
            if (ticketNums <= 0) {
                break;
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->" + ticketNums--);

        }
    }
}

取钱:余额可能会出现负数

package thread;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;


public class UnSafeThreadTest2 {

    public static void main(String[] args) {
        Account a = new Account("总金额", 100);
        Drawing you = new Drawing(a, 80, "wwkkkkkkk");
        Drawing me = new Drawing(a, 70, "wwwwwwwwww");
        you.start();
        me.start();
    }

}

class Drawing extends Thread {

    Account account;
    int drawingMoney;
    int packetMoney;

    public Drawing(Account account, int drawingMoney, String name) {
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    @Override
    public void run() {
        if (account.getMoney() < drawingMoney) {
            return;
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        account.setMoney(account.getMoney() - drawingMoney);
        packetMoney += drawingMoney;
        System.out.println(this.getName() + "账户余额-->" + account.getMoney());
        System.out.println(this.getName() + "取出金额-->" + packetMoney);
    }
}

@Setter
@Getter
@AllArgsConstructor
class Account {
    private String name;
    private int money;
}

操作容器:数据被覆盖

package thread;

import java.util.ArrayList;
import java.util.List;


public class UnSafeThreadTest3 {

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

线程同步(同步块/同步方法)synchronized

synchronized同步方法
package thread;


public class ThreadSynchronizedMethodTest {

    public static void main(String[] args) {

        ShopTicket st = new ShopTicket();
        new Thread(st, "wwk111").start();
        new Thread(st, "wwk222").start();
        new Thread(st, "wwk333").start();

    }
}

class ShopTicket implements Runnable {

    int ticketNum = 100;
    boolean flag = true;

    @Override
    public void run() {
        while (flag) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            runDetails();
        }
    }

    public synchronized void runDetails() {
        if (ticketNum <= 0) {
            flag = false;
            return;
        }
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "->" + ticketNum--);
    }
}

synchronized同步块
package thread;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;


class ThreadSynchronizedMethodTest1 {

    public static void main(String[] args) {
        Bank b = new Bank("wwk", 100);
        BankDraw d1 = new BankDraw(b, 80);
        BankDraw d2 = new BankDraw(b, 90);
        new Thread(d1, "wwk111").start();
        new Thread(d2, "wwk222").start();
    }
}

class BankDraw implements Runnable {

    Bank bank;
    int needMoney;
    int getMoney;

    public BankDraw(Bank bank, int needMoney) {
        this.bank = bank;
        this.needMoney = needMoney;
    }

    @Override
    public void run() {
        synchronized (bank) {
            if (bank.getMoney() < needMoney) {
                return;
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            bank.setMoney(bank.getMoney() - needMoney);
            getMoney = needMoney;
            System.out.println(Thread.currentThread().getName() + "取出金额:" + getMoney);
            System.out.println(Thread.currentThread().getName() + "剩余余额:" + bank.getMoney());
        }
    }
}

@Setter
@Getter
@AllArgsConstructor
class Bank {
    private String name;
    private int money;
}

线程性能分析
package thread;


public class ThreadSynchronizedAnalyze {

    public static void main(String[] args) {

        WwkTicket wt = new WwkTicket();
        new Thread(wt, "wwk111").start();
        new Thread(wt, "wwk222").start();
        new Thread(wt, "wwk333").start();
    }
}

class WwkTicket implements Runnable {

    private int ticketNum = 100;
    private boolean flag = true;


    @Override
    public void run() {
        while (flag) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            test5();
        }
    }

    //方式五:直接使用同步块,线程安全,尽可能锁住合理的范围
    private void test5() {
        //此处的判断考虑在没有票的时候停止线程
        if (ticketNum <= 0) {
            flag = false;
            return;
        }
        synchronized (this) {
            //此处用来判断最后一张票的情况
            if (ticketNum <= 0) {
                flag = false;
                return;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->" + ticketNum--);
        }
    }

    //方式四:直接使用同步块,线程不安全,范围太小锁不住
    private void test4() {
        synchronized ((Integer) ticketNum) {
            if (ticketNum <= 0) {
                flag = false;
                return;
            }
        }
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "-->" + ticketNum--);
    }

    //方式三:直接使用同步块,线程不安全,ticketNum对象(地址)一直在变化,锁不住
    private void test3() {
        synchronized ((Integer) ticketNum) {
            if (ticketNum <= 0) {
                flag = false;
                return;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->" + ticketNum--);
        }
    }

    //方式二:直接使用同步块,线程安全,范围太大效率低
    private void test2() {
        synchronized (this) {
            if (ticketNum <= 0) {
                flag = false;
                return;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->" + ticketNum--);
        }
    }

    //方式一:直接使用同步方法,线程安全
    private synchronized void test1() {
        if (ticketNum <= 0) {
            flag = false;
            return;
        }
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "-->" + ticketNum--);
    }
}

多线程购票典例
package thread;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;


public class CinemaTicket {

    public static void main(String[] args) {

        List seatList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            seatList.add(i);
        }

        List wwkSeats = new ArrayList<>();
        wwkSeats.add(1);
        wwkSeats.add(2);
        wwkSeats.add(3);
        wwkSeats.add(4);
        List wwhSeats = new ArrayList<>();
        wwhSeats.add(7);
        wwhSeats.add(8);
        wwhSeats.add(9);
        wwhSeats.add(5);

        Cinema c = new Cinema(seatList, "Cinema");
        Customer c1 = new Customer(c, wwkSeats);
        Customer c2 = new Customer(c, wwhSeats);

        new Thread(c1, "wwk").start();
        new Thread(c2, "wwh").start();


    }
}

class Customer implements Runnable {

    private Cinema cinema;
    private List seats;

    public Customer(Cinema cinema, List seats) {
        this.cinema = cinema;
        this.seats = seats;
    }

    @Override
    public void run() {
        synchronized (cinema) {
            boolean flag = cinema.bookTicket(seats, Thread.currentThread().getName());
            if (flag) {
                System.out.println(Thread.currentThread().getName() + "-->购票成功-->座位号为:" + seats.toString());
            } else {
                System.out.println(Thread.currentThread().getName() + "-->购票失败-->请重新选择座位号。");
            }
        }
    }
}

class Cinema {

    
    private List available;
    
    private String name;

    public Cinema(List available, String name) {
        this.available = available;
        this.name = name;
    }

    
    public boolean bookTicket(List seats, String name) {
        List temp = new ArrayList<>();
        temp.addAll(available);
        temp.removeAll(seats);
        if (temp.size() + seats.size() != available.size()) {
            return false;
        }
        available = temp;
        return true;
    }
}
解决线程之间的通信问题(wait/notify/notifyAll)
方法名作用
final void wait()表示线程一致等待,直到其他线程通知,与sleep不同,会释放锁
final void wait(long timeout)指定等待的毫秒数
final void notifiy()唤醒一个处于等待状态的线程
final void notifyAll()唤醒同一对象上所有调用wait()方法的线程,优先级别高的线程优先调度。
多线程并发协作生产者消费者模式(wait/notify/notifyAll) 管程法
package ProducerConsumerModel;

import lombok.*;


public class MonitorMethod {

    public static void main(String[] args) {
        MonitorContainer mc = new MonitorContainer();
        new Producer(mc).start();
        new Customer(mc).start();
    }

}


class Producer extends Thread {

    MonitorContainer mc;

    public Producer(MonitorContainer mc) {
        this.mc = mc;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("生产第" + i + "个商品");
            mc.push(new Commodity(i));
        }
    }
}


class Customer extends Thread {

    MonitorContainer mc;

    public Customer(MonitorContainer mc) {
        this.mc = mc;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费第" + mc.pop().getId() + "个商品");
        }
    }
}


class MonitorContainer {

    
    Commodity[] commodities = new Commodity[10];
    
    int count = 0;

    
    public synchronized void push(Commodity com) {
        //判断容器是否存在空间,如果存在则能生产,否则不能生产进入等待模式
        if (count == commodities.length) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        commodities[count] = com;
        count++;
        this.notifyAll();
    }

    
    public synchronized Commodity pop() {
        //判断容器中是否存在数据,若有数据进行读取处理数据,否则进行等待
        if (count == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        count--;
        Commodity temp = commodities[count];
        this.notifyAll();
        return temp;
    }
}


@Setter
@Getter
@AllArgsConstructor
class Commodity {

    
    private int id;
}
信号灯法
package ProducerConsumerModel;

import lombok.*;


public class LightMethod {

    public static void main(String[] args) {
        LightSign ls = new LightSign();
        new Producer2(ls).start();
        new Customer2(ls).start();
    }

}


class Producer2 extends Thread {

    LightSign ls;

    public Producer2(LightSign mc) {
        this.ls = mc;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            ls.production(i);
        }
    }
}


class Customer2 extends Thread {

    LightSign ls;

    public Customer2(LightSign mc) {
        this.ls = mc;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            ls.consumption();
        }
    }
}


class LightSign {

    
    boolean sign = true;

    int i;

    
    public synchronized void production(int i) {
        //判断标识位,消费者等待
        if (!sign) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //生产者进行生产
        System.out.println("生产第" + i + "个商品");
        this.i = i;
        this.notifyAll();
        //切换标识位
        this.sign = !this.sign;
    }

    
    public synchronized void consumption() {
        //判断标识位,生产者者等待
        if (sign) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //生产者进行生产
        System.out.println("消费第" + this.i + "个商品");
        this.notifyAll();
        //切换标识位
        this.sign = !this.sign;
    }
}


@Setter
@Getter
@AllArgsConstructor
class Commodity2 {

    
    private int id;
}

定时调度

Timer

package thread;

import java.util.GregorianCalendar;
import java.util.Timer;
import java.util.TimerTask;


public class TimerTest {

    public static void main(String[] args) {
        //定时器
        Timer t1 = new Timer();
        //定义任务
        MyTask task1 = new MyTask();
        //3秒之后执行
//        t1.schedule(task1, 3000);
        //5秒后,每个1秒执行一次
//        t1.schedule(task1, 3000, 1000);
        //指定时间执行
        GregorianCalendar calendar = new GregorianCalendar(2021, 10, 6, 19, 50, 59);
        t1.schedule(task1, calendar.getTime());
    }

}

class MyTask extends TimerTask {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("任务" + i);
        }
    }
}

Quartz

------

指令重排HappenBefore

-----

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/440034.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号