Java:多线程

多线程

启动 一个java程序 == 启动一个JVM进程,从而JVM的主线程调用main方法,同时main方法可以调用其他的线程

创建线程的方法

Thread t = new Thread();//创建一个新线程

t.start();//启动线程

  1. 创建一个类继承Thread类,并重写run方法(start方法内部调用了run方法)

    public class Main {
        public static void main(String[] args) {
            Thread t = new MyThread();
            t.start(); // 启动新线程
        }
    }
    
    class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("start new thread!");
        }
    }
    
  2. 创建Thread实例时传入Runnable实例(这个实例实现了Runnable接口,重写了run方法)

    public class Main {
        public static void main(String[] args) {
            Thread t = new Thread(new MyRunnable());
            t.start(); // 启动新线程
        }
    }
    
    class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("start new thread!");
        }
    }
    

多线程的使用细节

public class Main {
    public static void main(String[] args) {
        System.out.println("main start...");//1
        Thread t = new Thread() {//2
            public void run() {
                System.out.println("thread run...");//5
                System.out.println("thread end.");//6
            }
        };
        t.start();//3
        System.out.println("main end...");//4
    }
}

main线程执行了1,2,3,4语句,但是当**t.start()**执行时,run()方法和4语句是并发执行,且由操作系统调度,所以4,5,6的执行顺序无法预知

可以用Thread.sleep()方法强迫当前线程暂停一段时间,从而实现线程的同步和互斥

public class Main {
    public static void main(String[] args) {
        System.out.println("main start...");//1
        Thread t = new Thread() {
            public void run() {
                System.out.println("thread run...");//2
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {}
                System.out.println("thread end.");//3
            }
        };
        t.start();
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {}
        System.out.println("main end...");//4
    }
}

执行顺序为1->2->3->4,注意sleep()的单位是毫秒

Thread实例直接调用run()方法对多线程来言是无效的

public class Main {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.run();
    }
}

class MyThread extends Thread {
    public void run() {
        System.out.println("hello");
    }
}

以上相当于在main方法中调用了MyThread实例的run方法,并没有启动新线程

必须使用Thread实例的start方法才能启动新线程

线程的状态

  • New:新创建的线程,尚未执行;
  • Runnable:运行中的线程,正在执行run()方法的Java代码;
  • Blocked:运行中的线程,因为某些操作被阻塞而挂起;
  • Waiting:运行中的线程,因为某些操作在等待中;
  • Timed Waiting:运行中的线程,因为执行sleep()方法正在计时等待;
  • Terminated:线程已终止,因为run()方法执行完毕。

可以调用join()方法,等待当前线程执行结束再往下执行

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            System.out.println("hello");
        });
        System.out.println("start");
        t.start();
        t.join();
        System.out.println("end");
    }
}


中断线程

对目标线程调用interrupt()方法,通知该线程中止(并不是立即中止)

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new MyThread();
        t.start();
        Thread.sleep(1); // 暂停1毫秒
        t.interrupt(); // 中断t线程
        t.join(); // 等待t线程结束
        System.out.println("end");
    }
}

class MyThread extends Thread {
    public void run() {
        int n = 0;
        while (! isInterrupted()) {
            n ++;
            System.out.println(n + " hello!");
        }
    }
}

t.interrupt()改变了interrupted状态,故退出循环

执行t.join()使得main线程等待t线程结束,如果此时对main线程调用interrupt(),则join()方法会抛出InterruptedException异常。目标线程只要捕获到join()方法抛出的InterruptedException,就说明有其他线程对其调用了interrupt()方法,通常情况下该线程应该立刻结束运行

线程同步

解决多个线程同时读写共享变量时,出现数据不一致的问题

使用synchronized关键字对一个对象加锁,保证一段代码的原子性

synchronized保证代码块在任意时刻最多只有一个线程能执行

public class Main {
    public static void main(String[] args) throws Exception {
        var add = new AddThread();
        var dec = new DecThread();
        add.start();
        dec.start();
        add.join();
        dec.join();
        System.out.println(Counter.count);
    }
}

class Counter {
    public static final Object lock = new Object();
    public static int count = 0;
}

class AddThread extends Thread {
    public void run() {
        for (int i=0; i<10000; i++) {
            synchronized(Counter.lock) {
                Counter.count += 1;
            }
        }
    }
}

class DecThread extends Thread {
    public void run() {
        for (int i=0; i<10000; i++) {
            synchronized(Counter.lock) {
                Counter.count -= 1;
            }
        }
    }
}
synchronized(Counter.lock) { // 获取锁
    ...
} // 释放锁

使用Counter.lock实例作为锁,必须先获得锁,才能进入代码块执行,执行后自动释放锁

synchronized的使用:

  1. 找出修改共享变量的线程代码块;
  2. 选择一个共享实例作为锁;
  3. 使用synchronized(lockObject) { ... }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值