Java并行程序基础总结

来源:互联网 发布:linux 没法解压tar.gz 编辑:程序博客网 时间:2024/06/14 11:23

进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。

线程的生命周期

线程的所有状态都在Thread中的State枚举中定义

public enum State{    NEW,    RUNNABLE,    BLOCKED,    WALTING,    TIMED_WAITING,    RERMINATED;}

NEW状态表示刚刚创建的线程,这种线程还没开始执行,等到线程的start()方法调用时,才表示线程开始执行,当线程执行时,处于RUNNABLE状态,表示线程所需的一切资源都已经准备好了,如果线程在执行过程中遇到synchronized同步快,就会进入BLOCKED阻塞状态,这时线程就会暂停执行,直到获取请求锁,WAITING和TIMED_WAITING,都表示等待状态,区别在于WAITING会进入无时间限制的等待,TIMED_WAITING会进入有时限的等待中,线程执行完毕后,则进入RERMINATED状态,表示结束。

1、新建线程

  • 继承Thread类
Thread t1=new Thread(){    @Override    public void run(){        System.out.println("Hello");    }};t1.start();
  • 实现Runnable接口
public interface Runnable(){    public abstractvoid run();}public class Demo implements Runnable{    @Override    public void run(){        System.out.println("Runnable");    }    public static void main(String[] args){        Thread t1=new Thread(new Demo());        t1.start();    }}

2、终止线程

  • Thread提供了一个stop()方法,立即停止一个线程,但是这是一个已经被废弃的方法,stop过于暴力,强行把执行到一半的程序结束,这样会造成数据不一致的现象。

  • 设计一个标记变量flag=false;如果flag=true就让线程停止。

3、线程中断

线程中断的有三个方法

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

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

public final void wait() throws InteruptedExceptionpublic final native void notify()

这两个方法不是Thread类中的,而是Object类中的
Object.wait()方法并不是可以随便用的,他必须包含在对应的synchronzied语句中,无论时wait()和notify()都需要 先获得一个目标对象的一个监视器。
Object.wait()和Thread.sleep()方法都可以让线程等待若干时间,除了wait()可以被唤醒外,另一个主要区别就是wait()方法会释放目标对象的锁,而Thread.sleep()方法不会释放任何资源

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

这两个方法也是早已废弃的方法suspend()在导致线程暂停的同时,并不会去释放任何资源。

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

join()的本质是让调用线程wait()在当前线程对象实例上,如果你觉得一个线程没有那么重要,或者优先级非常低,而且又害怕占用太多的CPU资源,那么可以在适当的时候调用Thread.yield(),给予其他重要线程更多的工作机会

7、volatile

这个单词的解释“易变的,不稳定的”,当你用volatile去申明一个变量时,就等于告诉了虚拟机,这个变量极有可能会被某些程序或者线程修改
根据编译器的优化原则,如果不使用volatile申明变量,那么这个变量被修改后,其他线程可能并不会被通知到,甚至在别的线程中,看到变量的修改顺序都会是反的,但一旦使用volatile,虚拟机就会特别小心的处理这种情况。

8、线程组

public class ThreadGroupName implements Runnable{    /**     *线程组两个重要功能     * 1、activeCount()可以获得活动线程的总数     * 2、list()方法可以打印这个线程组中所有的线程信息     */    @Override    public void run() {        String groupAndName=Thread.currentThread().getThreadGroup().getName()+"-"+Thread.currentThread().getName();        while(true){            System.out.println("I am "+groupAndName);            try {                Thread.sleep(3000);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public static void main(String[] args) {        ThreadGroup tg=new ThreadGroup("PrintGroup");//线程组的名字        Thread t1=new Thread(tg,new ThreadGroupName(),"T1");//线程的名字T1        Thread t2=new Thread(tg,new ThreadGroupName(),"T2");        t1.start();        t2.start();        System.out.println(tg.activeCount());        tg.list();    }}

9、守护线程(Daemon)

public class DaemonDemo {    /**     * 守护线程例如垃圾回收线程,JIT线程     *     */    public static class DaemonT extends Thread{        public void run(){            while(true){                System.out.println("I am alive");                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }    public static void main(String[] args) throws InterruptedException {        Thread t=new DaemonT();        t.setDaemon(true);//将t线程设置成守护线程,必须在start之前,将当前进程变成后台进程。        t.start();        Thread.sleep(2000);    }}

系统中只有主线程main为用户线程,因此在main线程休眠2秒后退出时,整个程序也随着结束,但如果不把线程t设置为守护线程,main结束后,t线程还会继续打印,永远不会结束。

10、线程的优先级

public final static int MIN_PRIORITY=1;public final static int NORM_PRIORITY=5;public final static int MAX_PRIORITY=10;

数字越大,优先级越高。

11、线程安全的概念和synchronized

volatile并不能真正的保证线程安全。它只能确保一个线程被修改了数据后,其他线程能够看到这个改动。
关键字synchronized可以有多种用法,简单的整理一下
- 指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。
- 直接作用于实例方法:相当于对当前实例加锁,进入同步块前要获得当前实例的锁。
- 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁

12、并发下的ArrayList

ArrayList是一个线程不安全的容器,因为在ArrayList在扩容过程中,内部一致性被破坏,但由于没有锁的保护,另外一个线程访问到了不一致的内部状态,导致出现越界的问题。显然这是由于多线程访问冲突,使得保存容器大小的变量被多线程不正常的访问,同时两个线程也同时对ArrayList中的同一个位置进行赋值导致的。
最好的方式使用线程安全的Vector替代ArrayList即可

13、并发下的诡异的HashMap

当两个线程正在遍历HashMap的内部数据,当前所处循环乍看下时一个迭代遍历,就如同遍历一个链表一样,由于多线程冲突,这个链表的结构已经遭到破坏,链表被破坏了。有可能就会出现死循环之类ide问题
最简单的解决方案就是使用ConcurrentHashMap替代HashMap