Java线程--从入门到放弃

线程创建方式

1. Thread

package cn.huasheng.demo;

/**
 * Thread实现了runnable
 * 继承thread类
 * 重写run方法
 * 线程创建后,不会立即执行,要调用start方法
 */
public class ThreadDemo1 extends Thread{
    @Override
    public void run(){
        for (int i = 0; i < 200; i++) {
            System.out.println("a线程学习---"+i);
        }
    }

    public static void main(String[] args) {
        ThreadDemo1 demo1=new ThreadDemo1();
        demo1.start();System.out.println("主线程");

    }
}

2. Runnable

package cn.huasheng.demo;

/**
 * 实现runnable接口
 * 重写run方法
 * 执行线程需要掉入实现runnable接口的实现类,才能开启线程(推荐使用)
 *
 */
public class RunnableThread implements Runnable{
    public void run() {
        for (int i = 0; i <200 ; i++) {
            System.out.println(""+i);
        }
    }


    public static void main(String[] args) {
        RunnableThread rt=new RunnableThread();
        //代理方式
        new Thread(rt).start();
        System.out.println("main");
    }
}

3. Callable

package cn.huasheng.demo;

import java.util.concurrent.*;

/**
 * 实现callable接口
 *重写call方法
 * 有返回值,可以抛出异常
 */
public class CallableThread implements Callable<Boolean> {
    private String name;
    private String url;
    public CallableThread(String url,String name){
        this.url=url;
        this.name=name;
    }

    public Boolean call(){
        Down down=new Down();
        down.down(url,name);
        return true;
    }


    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CallableThread td1=new CallableThread("https://fanyi-cdn.cdn.bcebos.com/static/translation/img/header/logo_e835568.png","1.png");
        CallableThread td2=new CallableThread("https://fanyi-cdn.cdn.bcebos.com/static/translation/img/header/logo_e835568.png","2.png");

        CallableThread td3=new CallableThread("https://fanyi-cdn.cdn.bcebos.com/static/translation/img/header/logo_e835568.png","3.png");

        //创建执行服务
        ExecutorService service= Executors.newFixedThreadPool(3);

        //提交执行
        Future<Boolean> future1= service.submit(td1);
        Future<Boolean> future2= service.submit(td2);
        Future<Boolean> future3= service.submit(td3);
        //获取结果
        boolean res1=future1.get();
        boolean res2=future2.get();
        boolean res3=future3.get();
        System.out.println(res1+""+res2+""+res3);

        //关闭服务
        service.shutdown();

    }

}


class Down{
    public void down(String url,String name)  {
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        }catch (Exception e){

        }
    }
}

线程状态

新建NEW->就绪(WAITING)/等待(TIED WAITING)->阻塞(BLOCKED)->运行(RUNNABLE)>-死亡(TERMIMATED)

线程中断或死亡,都不能再重新启动

package cn.huasheng;

/**
 * 观察线程状态
 */
public class ThreadState {
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });


        Thread.State state=thread.getState();//新建状态
        System.out.println(state);
        //启动后
        thread.start();
        state=thread.getState();//启动后当状态
        System.out.println(state);

        while(Thread.State.TERMINATED!=state){
            Thread.sleep(100);
            state=thread.getState();
            System.out.println(state);

        }


    }
}

停止线程

package cn.huasheng.demo;

/**
 * 1.建议线程正常停止,利用循环次数,不建议死循环
 * 2。建议使用标志位,设置标志位
 * 3。不要使用stop或destroy等过时或者jdk不建议使用等方法
 */
public class StopThread implements Runnable{
   private boolean flag=true;
    public void run() {
        int a=0;
    while (flag){
        a++;
        System.out.println("---"+a);
    }
    }
    public void stop(){
        this.flag=false;
    }

    public static void main(String[] args) {
        StopThread stopThread=new StopThread();
        Thread thread= new Thread(stopThread);
        thread.start();

        for (int i = 0; i < 100000; i++) {
            if(i==90000){
                stopThread.stop();
            }
        }
    }
}

线程方法

睡眠:sleep,不会释放锁

礼让:yied,礼让不一定成功,要看cpu的调度,看cpu心情

插队:join, 合并线程,待此线程执行完毕后,再执行其他线程,其他线程阻塞,相当于插队

优先级:priority,通过setter/getter方法设置优先级/获取优先级

守护线程:daemon,线程分用户线程和守护线程, 比如main()就是用户线程,System.gc()垃圾回收就是守护线程,虚拟机不用等待守护线程是否执行完毕,而虚拟机必须确保用户线程执行完毕

#### 代码例子
睡眠
package cn.huasheng.method;

/**
 * 线程睡眠
 */
public class SleepThread {
    public static void main(String[] args) throws InterruptedException {

        for (int i = 0; i <100; i++) {
            Thread.sleep(100);
            System.out.println(i);
        }

    }
}

礼让
package cn.huasheng.method;

/**
 * 线程礼让
 */
public class YieldThread implements Runnable{
    public static void main(String[] args) {

        YieldThread thread=new YieldThread();
        new Thread(thread,"A").start();
        new Thread(thread,"B").start();

    }

    public void run() {
       String name= Thread.currentThread().getName();
       System.out.println(name+"----1");
         Thread.yield();
        System.out.println(name+"----2");

    }
}

插队
package cn.huasheng.method;

/**
 * 测试join,先当于插队
 */
public class TestJoin implements Runnable{


    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(new TestJoin());
        thread.start();
        for (int i = 0; i < 1000; i++) {
            if(i==500){
                thread.join();//执行这个后,要等到线程跑完才能继续跑主线程
            }
            System.out.println("main"+i);
        }
    }

    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("vip thread"+i);
        }
    }
}

优先级
package cn.huasheng.method;
//测试线程优先级
//优先级范围1~10,不能超出,不然报错
//默认优先级是5
public class TestPriority implements Runnable {

    public static void main(String[] args) {
        TestPriority priority=new TestPriority();
        Thread thread1=new Thread(priority,"A");
        Thread thread2=new Thread(priority,"B");
        Thread thread3=new Thread(priority,"C");
        //设置优先级
        thread1.setPriority(1);
        thread2.setPriority(8);
        System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority());

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

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

守护线程
package cn.huasheng.method;
//测试守护线程
public class TestDaemon {
    public static void main(String[] args) {
        Thread thread=new Thread(new You());

        Thread thread1=new Thread(new God());
        thread1.setDaemon(true);//设置为守护线程
        thread.start();
        thread1.start();


    }
}

class God implements  Runnable{
    @Override
    public void run() {
        for (;;) {
            System.out.println("i am gad!");
        }
     }
}
class You implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i <36500 ; i++) {
            System.out.println(i);
        }
        System.out.println("game over");
    }
}

线程同步

多个线程操作同一个线程

并发:同一个对象被多个线程同时操作

队列和锁:保证线程安全,就如排队上厕所,锁就像是厕所的门锁

代码例子

1. 银行取钱
package cn.huasheng.sync;

//不安全的取钱
//两个人去取钱,账户
public class UnsafeBank {
    public static void main(String[] args) {
        Account account=new Account("创业基金",100);
        new Drawing(account,50,"you").start();
        new Drawing(account,100,"me").start();


    }
}
class Account{
 String name;
 int money;
 public Account(String name,int money){
    this.name=name;
    this.money=money;
 }
}

class Drawing extends Thread{
    private final Account account;//账户

    private final int drawingMoney;//每次要取的钱
    private  int nowMoney;//手里的钱

    public Drawing(Account account,int drawingMoney,String name){
        super(name);
        this.account=account;
        this.drawingMoney=drawingMoney;
       // this.nowMoney=nowMoney;
    }
    //取钱
    @Override
    public  void run(){
        synchronized (account){//加锁解决问题
            if(account.money-drawingMoney<0){//判读是否有钱
                System.out.println(this.getName()+"钱不够,取不了");
                return;
            }
            try {
                Thread.sleep(1000);
            }catch (Exception e){
                e.printStackTrace();
            }
            //卡内的钱
            account.money=account.money-drawingMoney;
            //手里的钱
            nowMoney=nowMoney+drawingMoney;
            System.out.println(account.name+"余额为:"+account.money);
            System.out.println(this.getName()+"手里的钱:"+nowMoney);
        }
    }
}
2. 购票
package cn.huasheng.sync;

/**
 * 不安全的买票
 * 线程不安全,有负数
 */
 public class UnsafeBuyTicket implements Runnable{
    private int ticketNum=10;//票
    private boolean flag=true;
    public void run() {
        //买票
        while (flag){
            try {
                buy();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    private synchronized void buy() throws InterruptedException {//加锁解决问题
        if(ticketNum<=0){
            flag=false;
            return;
        }
        Thread.sleep(100);
        System.out.println(Thread.currentThread().getName()+"拿了第"+ticketNum+"票");
        ticketNum--;
    }

    public static void main(String[] args) {
        UnsafeBuyTicket tr=new UnsafeBuyTicket();
        new Thread(tr,"lisi").start();
        new Thread(tr,"zhangsan").start();
        new Thread(tr,"wangwu").start();

    }
}

3. List集合
package cn.huasheng.sync;

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

//线程不安全的集合
public class UnsafeList {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                synchronized (list){//加锁解决问题
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        try {
            Thread.sleep(2000);
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

//JUC
package cn.huasheng.sync;

import java.util.concurrent.CopyOnWriteArrayList;

public class TestJUC {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(2000);
            System.out.println(list.size());
        }catch (Exception e){}
    }
}

synchronized与lock对比

synchronized为隐式锁(出了作用域自动释放锁),lock为显式锁,可重入锁(需要手动开启锁和关闭锁)

Lock只有代码块锁,synchronized有代码块锁和方法锁

Lock锁,具有很好的扩展性(提供的子类较多),性能好(JVM花费较少的时间来调度线程)

优先使用顺序:lock>同步代码快>同步方法

代码例子

synchronized

死锁问题与解决

package cn.huasheng.lock;
//死锁,多线程互相抱着对方需要的资源,然后形成僵持
public class DeadLock {
    public static void main(String[] args) {
        Makeup g1=new Makeup(0,"A");
        Makeup g2=new Makeup(1,"B");
        g1.start();
        g2.start();
    }
}

class Lipstick{

}
class Mirror{

}
class Makeup extends Thread{

    static Lipstick lipstick=new Lipstick();
    static Mirror mirror=new Mirror();//需要的资源只有👔,用static来保证只有一份

    int choice;//选择
    String girlName;//使用化妆品的人

    Makeup(int choice,String girlName){
        this.choice=choice;
        this.girlName=girlName;
    }

    //化妆(死锁写法)
    private void makeup() 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(2000);
                synchronized (lipstick){//获得口红的锁
                    System.out.println(this.girlName+"获得口红的锁");
                }
            }
        }
    }

    //化妆(解决死锁写法)

    private void makeupnolock() 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(2000);

            }
            synchronized (lipstick){//获得口红的锁
                System.out.println(this.girlName+"获得口红的锁");
            }
        }
    }

    @Override
    public void run(){
        try {
         makeup();//死锁
           // makeupnolock();//解决死锁
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
Lock
package cn.huasheng.jinjie;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {
    public static void main(String[] args) {
        Ticket ticket=new Ticket();
        new Thread(ticket).start();
        new Thread(ticket).start();
        new Thread(ticket).start();
    }
}

class Ticket implements Runnable{

    private int ticketNum=10;

   private final ReentrantLock lock=new ReentrantLock();//定义可重入锁

    @Override
    public void run() {
        while (true){

           try {
               lock.lock();

            if(ticketNum>0){

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                System.out.println(ticketNum);
                ticketNum--;
            }else{
                break;
            }
           }finally {
               lock.unlock();
           }


        }
    }
}

线程协作

生产者消费者模式:生产者生产产品告知服务员,服务员取货给消费者,或者消费者需要产品,告知服务员,服务员通知生产者生产产品(通知与等待)管程法

比如:红绿灯(信号灯法)

代码例子

管程法
package cn.huasheng.jinjie;

import java.util.List;

//测试:生产者模型,利用缓冲区解决:管程法
//生产者,消费者,缓冲区,产品
public class TestProdCus {
    public static void main(String[] args) {
        SynContainer container=new SynContainer();

        new Productor(container).start();
        new Consumer(container).start();
    }
}

//生产者
class Productor extends  Thread{
    SynContainer container;
    public Productor(SynContainer container){
        this.container=container;
    }
    //生产
    public void run(){
        for (int i = 1; i <=100; i++) {

            container.push(new Apple(i));
            System.out.println("生产了"+i+"个apple");
        }
    }
}
//消费者
class Consumer extends  Thread{
    SynContainer container;
    public Consumer(SynContainer container){
        this.container=container;
    }
    //消费
    public void run(){
        for (int i = 1; i <=100; i++) {
            System.out.println("消费了"+container.pop().seriNum+"个apple");

        }
    }
}
//产品:苹果
class Apple{
    int seriNum;
    public Apple(int seriNum){
        this.seriNum=seriNum;
    }
}
//缓冲区
class SynContainer{
    //容器大小
      Apple[] apples=new Apple[10];
      //容器计数器
    int count=0;

    //生产者放入产品
    public synchronized void push(Apple apple) {
        // 若果容器满了,就需要等待消费者
        if(count==apples.length){
            //通知消费者消费,生产等待
            try {
                this.wait();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        //若果没有满,就掉入产品
        apples[count]=apple;
         count++;
         //通知消费者消费
        this.notifyAll();

    }

    //消费者消费
    public synchronized Apple pop(){
        if(count==0){//判断是否能消费
            //等待生产,消费者等待
            //通知消费者消费,生产等待
            try {
                this.wait();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        //若可以消费
        count--;
        Apple apple=apples[count];
        //消费完,通知生产者生产
        this.notifyAll();
        return apple;
    }
}
信号灯法
package cn.huasheng.jinjie;
//测试生产者消费者问题2:信号灯法,标志位解决
public class TestPCFlag {
    public static void main(String[] args) {
        TV tv=new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}
//生产者-》演员
class Player extends Thread{
    TV tv;
    Player(TV tv){
        this.tv=tv;
    }
    public void run(){
        for (int i = 0; i <20 ; i++) {
            if(i%2==0){
                this.tv.play("七龙珠播放中");
            }else{
                this.tv.play("广告播放中");
            }
        }
    }
}
//消费者-》观众
class Watcher extends Thread{
    TV tv;
    Watcher(TV tv){
        this.tv=tv;
    }
    
   public void run(){
       for (int i = 0; i <20 ; i++) {
           this.tv.watch();
       }
    }
}
//节目
class TV{
    //演员表演,观众等待 true
    //观众观看,演员等待 false
    String voice;//表演的节目
    boolean flag=true;
    //表演
    public synchronized void  play(String voice){
        if(!flag){
            try {
                this.wait();
            }catch (Exception e){

            }
        }
        System.out.println("演员表演了:"+voice);
        //通知观众观看
        this.notifyAll();//通知唤醒
        this.voice=voice;
        this.flag=!this.flag;
    }
//观看
    public synchronized void  watch(){
        if(flag){
            try {
                this.wait();
            }catch (Exception e){
                
            }
        }
        System.out.println("观众看了:"+this.voice);
        //通知观众观看
        this.notifyAll();//通知唤醒
        this.voice=voice;
        this.flag=!this.flag;
    }
}

线程池

背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响大。

思路:提前创建好多个线程,放在线程池中,使用时直接获取,使用完放回池中。

优点

  1. 提高响应速度(减少创建新线程的时间)
  2. 降低资源消耗(重复利用线程池中的线程,不需要每次创建)
  3. 便于管理

代码例子

package cn.huasheng.jinjie;

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

//测试线程池
public class TestThreadPool {
    public static void main(String[] args) {
        //1.创建线程池
        ExecutorService service= Executors.newFixedThreadPool(10);//创建固定大小的线程池

        //2。执行
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());

        //3。关闭
        service.shutdownNow();
    }
}

class MyThread implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值