您的位置:首页 > 编程语言 > Java开发

java复习并发

2016-01-06 14:37 603 查看

java复习二

想复习一下Java并发,看 Java 特种兵 并发部分 感觉讲的不错,写一下读书笔记

两个使用线程的方法

实现Runnable接口的多线程

package myList;

public class threadtest {
public static void main(String[] args) {
ThreadTests ds1 = new ThreadTests("阿三");
ThreadTests ds2 = new ThreadTests("李四");

Thread t1 = new Thread(ds1);

Thread t2 = new Thread(ds2);

t1.start();
t2.start();
}
}

class ThreadTests implements Runnable {
private String name;

public ThreadTests(String name) {
this.name = name;
}

public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + ": " + i);
}
}
}

//李四: 0
阿三: 0
李四: 1
阿三: 1
阿三: 2
李四: 2
李四: 3
阿三: 3
阿三: 4
李四: 4


2.扩展Thread类实现的多线程

package myList;

public class TestThread extends Thread {
public TestThread(String name) {
super(name);
}

public void run() {
for(int i = 0;i<5;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.getName()+" :"+i);
}
}

public static void main(String[] args) {
Thread t1 = new TestThread("阿三");
Thread t2 = new TestThread("李四");
t1.start();
t2.start();
}
}

//李四 :0
阿三 :0
李四 :1
阿三 :1
阿三 :2
李四 :2
阿三 :3
李四 :3
阿三 :4
李四 :4


new Thread()操作没有完成对线程的创建,只有当调用start()方法时才会真正在系统中存在一个线程,Thread本身对应的实例只是JVM内一个普通Java对象,是一个线程操作的外壳,而不是真正的线程。

线程状态

1.NEW 状态

表示线程还没有启动,只是创建了一个Java外壳,要注意的是调用了start()方法不表示状态就立即改变。

2.RUNNABLE 状态

程序运行状态,任务也有可能处于等待状态

3.BLOCKED 状态

BLOCKED称为阻塞状态,原因通常是它在等待一个锁

4.WAITING 状态

通常是指一个线程拥有对象锁后进入到相应的代码区域后,调用相应的锁对象的wait()方法操作后产生的一种结果,与BLOCKED状态比较,BOLOCKED状态是虚拟机认为程序还不能进入某个区域,发生wait()操作的条件就是要进入临界区,只是还有一些其他配合的资源没有准备充分,所有产生了等待。

notify()方法是唤醒一个处于WAITING状态的线程

5.TIMED_WAITING 状态

Thread.sleep()就可以进入TIMED_WAITING状态

6.TERMINATED 状态

线程结束时的状态,run()方法执行完成

wait()与notify()

它们都使用synchronized,它们的实现是基于对象,

interrupt()

interrupt()操作在线程处于BLOCKEN, RUNNING状态没有作用,只对WAITING, TIME_WAITING状态的线程有用,让它们产生异常

还可以通过isInterrupt()判断线程是否已经被调用过中断方法

stop()与interrupt()

interrupt()是相对缓和的处理方式,stop()对处于RUNNING状态的任务会导致任务直接抛出java.lang.ThreadDeath的Error,会有一定的风险。

线程优先级

Java提供了1-10个优先级,理论上数字越大优先级越高

可以通过setPriority()来设置优先级

在JVM中还有一种特殊的后台线程,可以通过setDaemon(boolean)设置是否为后台线程,它通常优先级很低,JVM的GC线程就是后台线程,后台线程有一种很重要的的特征,如果JVM进程中活着的线程只有后台线程,就要结束整个进程。

线程合并(Join)

package myList;

class ThreadTesterA implements Runnable {

private int counter;

@Override
public void run() {
while (counter <= 10) {
System.out.print("Counter = " + counter + " ");
counter++;
}
System.out.println();
}
}

class ThreadTesterB implements Runnable {

private int i;

@Override
public void run() {
while (i <= 10) {
System.out.print("i = " + i + " ");
i++;
}
System.out.println();
}
}

public class ThreadTester {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new ThreadTesterA());
Thread t2 = new Thread(new ThreadTesterB());
t1.start();
t1.join(); // wait t1 to be finished
t2.start();
t2.join(); // in this program, this may be removed
}
}

//i = 0 Counter = 0 Counter = 1 i = 1 Counter = 2 i = 2 Counter = 3 i = 3 Counter = 4 Counter = 5 Counter = 6 Counter = 7 Counter = 8 Counter = 9 Counter = 10
i = 4 i = 5 i = 6 i = 7 i = 8 i = 9 i = 10


可以实现同步的作用

线程安全

一致性问题一般出现在多核机器上

package myList;

public class ThreadTest extends Thread{

private boolean ready;

private int number;

public void run(){
while(!ready){
number++;
}
System.out.println(ready);
}

public void readyOn(){
this.ready = true;
}

public static void main(String [] args){
ThreadTest readThread = new ThreadTest();
readThread.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
readThread.readyOn();
System.out.println(readThread.ready);

}
}


代码可能会不能停止,因为不同变量的修改不需要立即写回到主存,而线程读取也不需要每一次去读取数据。

解决方法:1.在循环中添加一个Thread.yield(),操作就可以让线程让步CPU,进而很可能到主存中读取最新的ready的值。2.在循环中加一条System.out语句,或者将ready变量增加一个volatile修饰符也可以达到退出的目的。

ThreadLocal

ThreadLocal可以放一个线程级别的变量,但它本身可以被多个线程共享使用,而又达到线程安全的目的,且绝对线程安全。

public final static ThreadLocal<String> RESOURCE = new ThreadLocal<String>();


RESOURCE代表一个可以存放String类型的ThreadLocal对象,任何一个线程可以并发访问这个变量,对它进行写入,读取操作,都是线程安全的

原子性和锁

synchronized

synchronized通过在对象上加锁后进入临界区达到临界区串行访问的目的

1.普通方法前面加synchronized

synchronized public void test() {}


锁住了类的对象

2. 静态方法前面加synchronized

synchronized public static void test() {}


锁住了当前类

3. 代码块加锁

synchronized(object){
//代码
}


锁住的不是代码而是object对象
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息