线程基础

本文详细介绍了Java线程的基础知识,包括线程的创建与使用、线程的状态与属性、线程间的同步机制等内容,并通过生产者消费者模式展示了线程同步的具体应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、线程的使用

1.1 线程的使用有两种方式:继承Thread、继承Runnable

//使用继承Thread方式
class MThread extends Thread {
    @Override
    public void run() {
        System.out.println("==>MThread run");
    }
}

class MRun implements Runnable{
    private boolean isRun = true;
    @Override
    public void run() {
        while(isRun)
            System.out.println("==>MRun");
    }
    //停止线程的最好方式
    public void stop(){
        this.isRun = false;
    }
}

public class Test {
    public static void main(String[] args){
        //使用继承Thread方式
        new MThread().start();
        //使用实现Runnable的方式
        new Thread(new MRun()).start();
        //多线程共享同一个Runnable
        MRun run = new MRun();
        new Thread(run).start();
        new Thread(run).start();
    }
}

2、线程的状态

这里写图片描述
线程有6种状态
2.1 新建:new Thread()时的状态,此时并未运行run方法中的代码
2.2 可运行:一旦调用了start()方法,线程就处于可运行状态。但是此时线程可能正在运行,也可能没有运行
2.3 被阻塞:当线程试图获取锁,而该锁被其他线程持有,线程进入被阻塞状态。当获取锁时,线程变为非阻塞状态
2.4 等待:当线程等待另一个线程通知调度器一个条件,该线程将进入等待状态。在调用Object.wait、Thread.join时,会出现等待状态。
等待状态与被阻塞状态不同
2.5 超时:有些方法有超时参数,调用他们将使线程进入计数等待状态。这一状态将一直保持到超时或者收到适当的通知。这些方法有Thread.sleep/Lock.tryLock
2.6 被终止
线程终止有两种方式:
run方法执行完
一个未捕获的异常导致run方法意外退出

当线程被阻塞、等待时,另一个线程被调度为可运行状态。当该线程重新被激活进入可运行状态,调度器会检查它是否具有比正在运行线程更高的优先级,如果更高,调度器会暂停一个正在运行的线程,运行此线程。

3、线程属性

3.1 线程的优先级

每个线程都有一个优先级,默认情况下会继承父类的优先级。使用setPriority方法可以设置,范围为1~10
线程的优先级高度依赖系统。sun为linux提供的线程优先级被忽略,即所有的优先级都相同

3.2 守护线程

Thread.setDaemon(true);方法将线程设置为守护线程。
守护线程唯一的作用就是为其他线程提供服务。当只剩下守护线程时,虚拟机会退出

3.3 interrupt

用来设置中断状态,true为中断状态。我们调用sleep、wait等此类可中断(throw InterruptedException)方法时,一旦方法抛出InterruptedException,当前调用该方法的线程的中断状态就会被jvm自动清除了。如果你想保持中断状态,可以再次调用interrupt方法设置中断状态。检测状态可以使用isInterrupted。标记为中断状态不会停止线程,需要用户做具体处理
interrupted返回的是当前线程的中断状态,同时将当前线程状态置位

3.4 未捕获异常处理器

线程的run方法不能抛出任何被检测的异常,不被检测的异常会导致线程终止。出异常的线程不会影响到其他线程,所以其他线程也不能知道一个线程因为异常而终止。
如果需要捕获这个异常,可以实现Thread.UncaughtExceptionHandler接口,或者使用Thread.setDefaultUncaughtExceptionHandler方法。
调用步骤:
如果该线程组有父线程组,则先调用父线程组的uncaughtException方法
如果Thread.getDefaultUncaughtExceptionHandler()返回一个非空处理器,调用之
如果Throwable是ThreadDeath的一个实例,则什么都不做
否则 线程名字及Throwable的栈踪迹被输出到System.err上
http://blog.youkuaiyun.com/u010853261/article/details/61419677

4、Callable和Future

4.1 Runnable封装一个异步执行任务,run方法没有参数、没有返回值
4.2 Callable与Runnable类似,但是有返回值且可以抛异常

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

4.3 Future 比Callable更强大

public interface Future<V> {
    //将会被阻塞,知道有返回值
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
            throws InterruptedException,ExecutionException, TimeoutException;
}

4.4 FutureTask
继承Runnable, Future

2、同步基础

2.1 synchronized

synchronized锁有两种用法:
锁方法
锁对象
锁对象时,要保证对象的唯一性。
同步是一种高开销的操作,因此应该尽量减少同步的内容。通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。

2.2 wait与notify

Object.wait使线程进入等待状态,直到它被其他线程通过notify()或者notifyAll唤醒。该方法只能在同步方法中调用,即Object.wait()和Object.notify()和Object.notifyall()必须写在synchronized方法内部或者synchronized块内部。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
void wait(long millis)超时版本

wait进入等待状态会释放锁,但是sleep不会
notifyAll在wait之前调用,不会影响到wait的线程

2.3 volatile

多线程下,每个线程获得的volatile修饰的变量都是最新值,不提供原子性

2.4 ThreadLocal

每个线程都有私有内存,使用私有内存,各个线程互不影响

2.5 原子变量
2.6 JUC

生产者消费者

class Service{
    public int index;
    public LinkedList<Integer> list = new LinkedList<Integer>();
    public final static int MAX = 100;

    public void produce() {
        synchronized (list) {
            try {
                //如果货物已满 则等待消费
                while (list.size() >= MAX) {
                    System.out.println(Thread.currentThread().getName()+"工厂==>仓库有  " + list.size()+"  个商品  已经无法生产");
                    list.wait();
                }

                this.list.offer(++this.index);
                System.out.println(Thread.currentThread().getName()+"工厂==>仓库有  " + this.list.size()+"  个商品");
                Thread.currentThread().sleep(50);

                list.notify();
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void custom() {
        synchronized (list) {
            try {
                //如果没有物品 需要等待生产
                while (this.list.size() <= 0) {
                    System.out.println(Thread.currentThread().getName()+"   消费==>仓库有  " + this.list.size()+"  个商品  等待工厂生产");
                    list.wait();
                }
                this.list.pop();
                System.out.println(Thread.currentThread().getName()+"消费==>仓库有  " + this.list.size()+"  个商品");
                Thread.currentThread().sleep(80);

                list.notify();
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

class Producer extends Thread{
    private Service service;

    public Producer(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        while(true)
            this.service.produce();
    }
}

class Customer extends Thread{
    private Service service;

    public Customer(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        while(true)
            this.service.custom();
    }
}

public class Test{
    public static void main(String[] args) {
        Service service = new Service();
        new Producer(service).start();
        new Producer(service).start();
        new Producer(service).start();
        new Customer(service).start();
        new Customer(service).start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值