java并发-线程

前言

近来时间比较充裕,正好又看了一遍《实战java高并发程序设计》,故而对java并发一些知识进行下总结,算是温故而知新吧。

一,线程基础

1,新建线程

一般有两种实现方式实现Runnable接口或继承Thread类(Thread类本身也是实现Runnable接口)

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1=new TestThread();
        Thread t2=new TestThread();
        Thread t3=new Thread(new TestThreadImpl());
        Thread t4=new Thread(new TestThreadImpl());
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        }
}
class TestThread extends Thread{
    @Override
    public void run() {
        System.out.println("hello word");
    }
}
class TestThreadImpl implements Runnable{
    @Override
    public void run() {
        System.out.println("hello word 2");
    }
}

2,线程的终止

一般来说线程在执行完毕后就会结束无须手动关闭,但凡是总有例外一下服务端的后台线程可能会常驻系统,比如它们本身就是一个无限循环,用于提供默写服务。

Thread 提供了一个被标注为废弃的方法stop();因为stop()方法过于暴力,强行把执行一般的线程终止,这样可能会引起一些数据不一致的问题。《实战java高并发程序设计》中给出了一个的解决方案,用一个一个自定义的stop并且需要自行决定何时退出

class ChangeObjectThread extends Thread{
    volatile boolean stopme=false;
    public void stopMe(){
        stopme=true;
    }
    @Override
    public void run() {
        while(true){
            if(stopme){
                break;
            }
            //synchromized handle data

        }
    }
}

3,线程中断interrupt

严格来讲,线程中断并不会让线程立即退出,而是给线程发送一个通知,告知目标线程 ,有人希望你退出了。至于目标线程街道通知后如何处理,则完全有线程自行决定,如果无条件退出那么又遇到和stop()相同的问题了。

public void interrupt() //中断线程
public boolean isInterrupted()//判断是否被中断
public static boolean interrupted()//判断是否被中断,并清除当前中断状态
public class Test {
    public static Object o = new Object();

    public static void main(String[] args) throws Exception {
        Thread t1 = new TestThread();
        t1.start();
        Thread.sleep(1000);
        t1.interrupt();
    }
}

class TestThread extends Thread {
    @Override
    public void run() {
        int i=0;
        while (!isInterrupted()) {
            i++;
            System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i);
        }
    }
}

另:当线程由于被调用了sleep(), wait(), join()等方法而进入阻塞状态;若此时调用线程的interrupt()将线程的中断标记设为true。由于处于阻塞状态,中断标记会被清除,同时产生一个InterruptedException异常,这时就要用合适的方式处理InterruptedException了

4,Object 等待(wait)和通知(notify)

这两个方法是由Object类提供的,并不是在Thread中的。当一个对象实例调用了wait()方法后,当前线程就会在这个对象上等待。如:线程A中调用了obj.wait()方法,那么线程A就会停止继续执行,而转为等待状态,直到调用了obj.notify()方法为止。

wait(),notify()方法的调用鼻血包含在对应的synchronized语句中,也就是要先获得目标对象锁资源。调用了wait后,会释放锁资源。

public class Test {
    public static Object o = new Object();

    public static void main(String[] args) throws Exception {
        Thread t1 = new TestThread();
        Thread t2 = new TestThread();
        Thread t3 = new TestThread();
        Thread t4 = new TestThreadNotify();
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }

}

class TestThread extends Thread {
    @Override
    public void run() {
        synchronized (Test.o) {
            try {
                System.out.println(Thread.currentThread().getName()+"waiting....");
                Test.o.wait();
                System.out.println(Thread.currentThread().getName()+"start....");
                Thread.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"stop....");
        }
    }
}

class TestThreadNotify extends Thread {
    @Override
    public void run() {
        synchronized (Test.o) {
            System.out.println("TestThreadNotify start....");
            try {
                Test.o.notifyAll();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("TestThreadNotify stop....");
        }
    }
}
}
Thread-0waiting....
TestThreadNotify start....
TestThreadNotify stop....
Thread-2waiting....
Thread-1waiting....
Thread-0start....
Thread-0stop....

5,等待线程结束(join)和谦让(yield)

很多时候,一个线程的输入可能非常依赖于另外一个或者多个线程的输出,此时,这个线程就需要等待依赖线程执行完毕,才能继续执行。JDK 提供了join()操作来实现这个功能,如下所示,显示了2个join()方法:

public final void join() throws InterruptedException

public final synchronized void join(long millis) throws InterruptedException

第一个join()方法表示无限等待,它会一直阻塞当前线程,直到目标线程执行完毕。

第二个方法给出了一个最大等待时间,如果超过给定时间目标线程还在执行,当前线程也会因为“等不及了”,而继续往下执行。

join()的本质是让调用线程wait()在当前线程对象实例上;

public class Test {
    public volatile static int i = 0;
    public static class AddThread extends Thread {
        @Override
        public void run() {
            for (i = 0; i < 10000000; i++);
        }
    }
    public static void main(String[] args) throws InterruptedException {
        AddThread at = new AddThread();
        at.start();
        at.join();
        System.out.println(i);

    }

}

主函数中,如果不使用join()等待AddThread ,那么得到的i 很可能是0或者一个非常小的数字。因为AddThread 还没开始执行,i 的值就已经被输出了。但在使用join()方法后,表示主线程愿意等待AddThread 执行完毕,跟着AddThread 一起往前走,故在join()返回时,AddThread 已经执行完成,故i 总是10000000

yiead()

这是一个静态方法,一旦执行,它会使当前线程让出CPU 。但要注意,让出CPU 并不表示当前线程不执行了。当前线程在让出CPU 后,还会进行CPU 资源的争夺,但是是否能够再次被分配到,就不一定了

待续

时间: 2024-10-09 17:53:04

java并发-线程的相关文章

Java 并发 线程同步

Java 并发 线程同步 @author ixenos 同步 1.异步线程本身包含了执行时需要的数据和方法,不需要外部提供的资源和方法,在执行时也不关心与其并发执行的其他线程的状态和行为 2.然而,大多数实际的多线程应用中,两个或两个以上的线程需要共享对同一数据的存取,这将产生同步问题(可见性和同步性的丢失) 比如两个线程同时执行指令account[to] += amount,这不是原子操作,可能被处理如下: a)将account[to]加载到寄存器 b)增加amount c)将结果写回acco

Java 并发 线程属性

Java 并发 线程属性 @author ixenos 线程优先级 1.每当线程调度器有机会选择新线程时,首先选择具有较高优先级的线程 2.默认情况下,一个线程继承它的父线程的优先级 当在一个运行的线程A里,创建另一个线程B的时候,那么A是父线程,B是子线程.当在一个运行的线程A里,创建线程B,然后又创建了线程C,这时候虽然B比C创建早,可是B并不是C的父线程,而A是B和C的父线程. 3.线程的优先级高度依赖于系统,当虚拟机依赖于宿主机平台的线程实现机制时,Java线程的优先级被映射到宿主机平台

Java 并发 线程的优先级

Java 并发 线程的优先级 @author ixenos 低优先级线程的执行时刻 1.在任意时刻,当有多个线程处于可运行状态时,运行系统总是挑选一个优先级最高的线程执行,只有当线程停止.退出或者由于某些原因不执行的时候,低优先级的线程才可能被执行 2.两个优先级相同的线程同时等待执行时,那么运行系统会以round-robin的方式选择一个线程执行(即轮询调度,以该算法所定的)(Java的优先级策略是抢占式调度!) 3.被选中的线程可因为一下原因退出,而给其他线程执行的机会: 1) 一个更高优先

Java 并发 线程的生命周期

Java 并发 线程的生命周期 @author ixenos 线程的生命周期 线程状态: a)     New 新建 b)     Runnable 可运行 c)     Running 运行 (调用getState()时显示为Runnable) d)     Blocked 阻塞 i.          I/O阻塞 (不释放锁) I/O操作完成解除阻塞,进入Runnable状态 ii.          同步阻塞(不释放锁) 运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会

java并发-线程饥饿死锁测试

线程饥饿死锁 <Java并发编程实践>中对线程饥饿死锁的解释是这样的:在使用线程池执行任务时,如果任务依赖于其他任务,那么就可能产生死锁问题.在单线程的Executor中,若果一个任务将另一个任务提交到同一个Executor,并且等待这个被提交的任务的结果,那么这必定会导致死锁.第一个任务在工作队列中,并等待第二个任务的结果:而第二个任务则处于等待队列中,等待第一个任务执行完成后被执行.这就是典型的线程饥饿死锁.即使是在多线程的Executor中,如果提交到Executor中的任务之间相互依赖

Java并发——线程间的等待与通知

前言: 前面讲完了一些并发编程的原理,现在我们要来学习的是线程之间的协作.通俗来说就是,当前线程在某个条件下需要等待,不需要使用太多系统资源.在某个条件下我们需要去唤醒它,分配给它一定的系统资源,让它继续工作.这样能更好的节约资源. 一.Object的wait()与notify() 基本概念: 一个线程因执行目标动作的条件未能满足而被要求暂停就是wait,而一个线程满足执行目标动作的条件之后唤醒被暂停的线程就是notify. 基本模板: synchronized (obj){ //保护条件不成立

Java 并发 – 线程安全?

线程安全的定义常常让人迷惑,搜索引擎会发现无数定义,比如: 多个线程同时执行也能正确工作就是线程安全的代码 多个线程同时执行能以正确的方式操纵共享数据就是线程安全的代码. 而且还有很多类似的定义 你是否认为这种定义实际上没有任何意义而且还让人更加迷惑?虽然这些定义没错,但事实是他们没有提供任何实际的帮助或观点.我们如何区分线程安全类和不安全类?我们所谓的"安全"是什么意思? 线程安全的正确性是什么? 线程安全的任何合理定义的核心是正确性的概念.因此,在了解线程安全之前,我们首先应该理解

Java并发——线程间通信与同步技术

传统的线程间通信与同步技术为Object上的wait().notify().notifyAll()等方法,Java在显示锁上增加了Condition对象,该对象也可以实现线程间通信与同步.本文会介绍有界缓存的概念与实现,在一步步实现有界缓存的过程中引入线程间通信与同步技术的必要性.首先先介绍一个有界缓存的抽象基类,所有具体实现都将继承自这个抽象基类: public abstract class BaseBoundedBuffer<V> { private final V[] buf; priv

Java并发-线程安全性

首先了解一下多线程的概念 多线程:两段或以上的代码同时进行,多个顺序执行流. 并发和并行的区别 并发:做一下这个做一下那个. 并行:同时进行. 线程和进程的区别 进程:资源分配的基本单位,运行中的程序.进程中包括多个线程,线程们共享进程的资源. 线程:处理器调度的基本单位. 线程的状态:  线程创建的方法: (1)继承Thread类 (2)实现Runnable接口 (3)匿名内部类.Lambda表达式 (4)带返回值的线程 要想使对象是线程安全的,需要采用同步机制来协同,如果无法实现,那么可能会