Java并行程序基础总结

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

线程的生命周期

线程的所有状态都在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 InteruptedException
public 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值