2.Java 并行程序基础

1.初始线程:线程的基本操作

1.新建线程

2.终止线程

  • stop

造成数据不一致

3.线程中断

public void Thread.interrupt()              // 中断线程
public boolean Thread.isTnterrupted()        // 判断是否被中断
public static boolean Thread.interrupted()  // 判断是否被中断,并清除当前中断状态

4.等待(wait)和通知(notify)

public final void wait() throws InterruptedException
public final native void notify()
//
public static native void sleep(long millis) throws InterruptedException

Object.wait()和Thread.sleep()方法都可以让线程等待若干时间。除了wait()可以被唤醒外,另外一个主要区别就是wait()方法会释放目标对象的锁,而Thread.sleep()方法不会释放任何资源。

Object.wait()方法并不是可以随便调用的。它必须包含在对应的synchronzied语句中,无论是wait()或者notify()都需要首先获得目标对象的一个监视器。

5.挂起(suspend)和继续执行(resume)线程

suspend() 在导致线程暂停的同时,并不会取释放任何锁资源。

6.等待线程结束(join)和谦让(yield)

join
public final void join() throws InterruptedException
public final synchronized void join(long millis) throws InterruptedException

join:一个线程的输入可能非常依赖另外一个或者多个线程的输出,此时这个线程就需要等待依赖线程执行完毕,才能继续执行。

  • join():无限等待,它会一致阻塞当前线程,直到目标线程执行完毕。
  • join(long millis):给出一个最大等待时间,如果超过给定时间目标线程还在执行,当前线程也会因为“等不及了”,而继续往下执行。

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

//核心代码
while (isAlive()) {
   wait(0);
}

它让调用线程在当前线程对象上进行等待。当线程执行完成后,被等待的线程会在退出前调用notifyAll() 通知所有的等待线程继续执行。因此,值得注意的一点是:不要在应用程序中,在Thread对象实例上使用类似wait()或者notify()等方法,因此这很有可能会影响系统API的工作,或者被系统API所影响

yield
public static native void yield();

2. volatile与Java内存模型(JMM)

volatile:使用volatile申明一个变量时,就等于告诉虚拟机,这个变量极有可能会被某些程序或者线程修改。为了确保这个变量被修改后,应用程序范围内的所有线程都能够“看到”这个改动,虚拟机就必须采用一些特殊的手段,保证这个变量的可见性等特点。

注意:volatile并不能代替锁?,它也无法保证一些符合操作的原子性。 例如:?

public class VolatileTest {

    volatile static int i = 0;

    public static class PlusTask implements Runnable{
        public void run(){
            for(int k = 0;k<10000;k++){
                i++;
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread[] threads = new Thread[10];
        for (int i = 0;i<10;i++){
            threads[i] = new Thread(new PlusTask());
            threads[i].start();
        }

        for (int i = 0;i<10;i++){
            threads[i].join();
        }
        System.out.println(i);
    }
}

volatile 也能保证数据的可见性和有序性

3.分门别类的管理:线程组

// 创建线程组
ThreadGroup tg = new ThreadGroup("PrintGroup");
// 使用Thread构造方法指定线程所属的县城组
Thread t = new Thread(tg,new ThreadTest(),"T1");

stop:慎用,它会停止线程组中所有的线程。和Thread.stop()一样。

4.驻守后台:守护线程(Daemon)

比如:垃圾回收线程、JIT线程

与之对应的是用户线程,当一个Java内,只有守护线程时,Java虚拟机就会自然退出。

public class DaemonDemo {
    public static class DaemonT extends Thread{
        public void run(){
            while(true){
                System.out.println("I'm alive");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t = new DaemonT();
        t.start();
        // 将t设置为守护线程
        t.setDaemon(true);
        Thread.sleep(3000);

    }
}

5.先干重要的事:线程优先级

使用1-10表示线程优先级。一般使用内置的三个静态标量表示:
数字越大则优先级越高。

/**
 * The minimum priority that a thread can have.
 */
public final static int MIN_PRIORITY = 1;

/**
 * The default priority that is assigned to a thread.
 */
public final static int NORM_PRIORITY = 5;

/**
 * The maximum priority that a thread can have.
 */
public final static int MAX_PRIORITY = 10;

6.线程安全的概念与synchronized

synchronized:是实现线程间的同步。它的工作是对同步的代码加锁,使得每一次,只能有一个线程进入同步块,从而保证线程间的安全性。

用法:

  • 指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。
  • 直接作用于实例方法:相当于对当前实例加锁,进入同步前要获得当前实例的锁
  • 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。

7.程序中的幽灵:隐蔽的错误

ArrayList 线程不安全 HashMap 线程不安全. ConcurrentHashMap代替

8.初学者常见问题:错误的加锁


参考文献: 《Java高并发设计》

转载于:https://my.oschina.net/idarex/blog/1593818

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值