Java 线程(一)

复习一下Java的线程 , 看了官网上的教程:http://download.oracle.com/javase/tutorial/essential/concurrency/index.html

对于并发,主要有线程和进程两种实现方式,区别很明显,java可以多进程:
使用ProcessBuilder(java.lang),
ProcessBuilder pb =
new ProcessBuilder("myCommand", "myArg1", "myArg2");
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory(new File("myDir"));
File log = new File("log");
pb.redirectErrorStream(true);
pb.redirectOutput(Redirect.appendTo(log));
Process p = pb.start();
assert pb.redirectInput() == Redirect.PIPE;
assert pb.redirectOutput().file() == log;
assert p.getInputStream().read() == -1;
(没有仔细看,待会儿,仔细看看)

对于Thread, java实现的两种方式:
1. 简单的new 一个, 然后start, 这样每个Thread都要赋予一个task
2. 把task放到一个executor中,交给系统去处理

简单的创建一个Thread,对于task的设置也有两种方式:
1. 继承Thread,然后重载run方法
2. 实现一个Runnable接口, 然后new Thread(runnalbe)的方式

一个Thread的一些操作:
1. sleep, sleep可以挂起一个线程,sleep(time), 挂起一定时间,当然由于OS的原因,time不是肯定能准确实现的, 同时sleep可以被interrupt, 这时会抛出InterruptedException , 所以一般在sleep的时候,都要对这个异常进行处理
比如,catch
for (int i = 0; i < importantInfo.length; i++) {
//Pause for 4 seconds
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
//We've been interrupted: no more messages.
return;
}
//Print a message
System.out.println(importantInfo[i]);
}
同时,Thread提供了interrupt的状态查询方法, Thread.interrupted(),
for (int i = 0; i < inputs.length; i++) {
heavyCrunch(inputs[i]);
if (Thread.interrupted()) {
//We've been interrupted: no more crunching.
return;
}
}

2. join, 会挂起当前线程,等待执行join的线程执行结束,返回
如: 在当前线程中使用 t.join(), t为另一个线程, 则当前线程等待t线程执行完毕
同时join会被interrupt, 抛出InterruptedException

同步: 这是在处理并发程序时,必须面对的,主要用于解决两种error
1. Thread Interference :是指在一个线程对一个对象进行一个操作时,另一个线程对当前对象的干扰, 比如: c++ 这个操作,虽然只有一行但是在JVM中会分成几步处理,这就会给其他线程在几步中干涉的机会
2. Memory Consistency Error 是指对于线程间共享的对象,一旦一个线程对其进行改变,对于另一个线程并一定是可见的

解决方法:
1. sychronized method: 对并发的方法声明synchronized, 这样就会在同时只有一个线程使用这个方法,可以有效的避免出现Thread Interference. 同时一个synchronized 的方法结束后,会产生happens-before 的效果,简单说就是操作结果对其他线程可见,避免了error2
注意:
1. constructor method是不能synchronized的, 因为同时对一个对象,只可能有一个线程new
2. final 变量是不能修改的,不需要对操作进行synchronized

2. synchronized statements: 对一些操作把,把他们放在synchronized语句块中,而不是简单的synchronized方法, 需要提供一个synchronized的对象。

synchronized 实现同步的原理, 还是通过锁机制,对于synchronized方法的锁,是由对象提供的,在获取锁后,执行方法,返回时释放锁(甚至在抛出异常时也会释放锁), 这种锁叫做: Intrinsic Lock, 提供了对于对象的单一访问和happens-before两种功能, 而synchronized statement 需要的对象,就是提供锁的对象。
注意: 对于static的方法的锁,是class的锁,而不是对象

对于锁使用的error :
1. deadLock, 常见错误, 简单说就是, 进入一个两个线程都在等待对方释放锁的状态。
具体看理解了。官网例子:
public class Deadlock {
static class Friend {
private final String name;
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public synchronized void bow(Friend bower) {
System.out.format("%s: %s has bowed to me!%n",
this.name, bower.getName());
bower.bowBack(this);
}
public synchronized void bowBack(Friend bower) {
System.out.format("%s: %s has bowed back to me!%n",
this.name, bower.getName());
}
}

public static void main(String[] args) {
final Friend alphonse = new Friend("Alphonse");
final Friend gaston = new Friend("Gaston");
new Thread(new Runnable() {
public void run() { alphonse.bow(gaston); }
}).start();
new Thread(new Runnable() {
public void run() { gaston.bow(alphonse); }
}).start();
}
}

2. starvation, 对于一个线程在synchronized的method中处理时间很长,就会造成其他线程j饥饿
3. liveLock , 一个线程是另一个线程的response,同时另一个线程又是其他线程的response,不停的link下去,就会造成liveLock,没碰到过,了解一下概念

wait和notify
Object中的方法wait, notify在多线程中应用,
对于需要等待的情况, 可以用wait将当前线程等待,使用notify可以唤醒,并且通过标志位进行控制。
看个例子就明白了:
public class Drop {
//Message sent from producer to consumer.
private String message;
//True if consumer should wait for producer to send message, false
//if producer should wait for consumer to retrieve message.
private boolean empty = true;

public synchronized String take() {
//Wait until message is available.
while (empty) {
try {
wait();
} catch (InterruptedException e) {}
}
//Toggle status.
empty = true;
//Notify producer that status has changed.
notifyAll();
return message;
}

public synchronized void put(String message) {
//Wait until message has been retrieved.
while (!empty) {
try {
wait();
} catch (InterruptedException e) {}
}
//Toggle status.
empty = false;
//Store message.
this.message = message;
//Notify consumer that status has changed.
notifyAll();
}
}

import java.util.Random;

public class Producer implements Runnable {
private Drop drop;

public Producer(Drop drop) {
this.drop = drop;
}

public void run() {
String importantInfo[] = {
"Mares eat oats",
"Does eat oats",
"Little lambs eat ivy",
"A kid will eat ivy too"
};
Random random = new Random();

for (int i = 0; i < importantInfo.length; i++) {
drop.put(importantInfo[i]);
try {
Thread.sleep(random.nextInt(5000));
} catch (InterruptedException e) {}
}
drop.put("DONE");
}
}

import java.util.Random;

public class Consumer implements Runnable {
private Drop drop;

public Consumer(Drop drop) {
this.drop = drop;
}

public void run() {
Random random = new Random();
for (String message = drop.take(); ! message.equals("DONE");
message = drop.take()) {
System.out.format("MESSAGE RECEIVED: %s%n", message);
try {
Thread.sleep(random.nextInt(5000));
} catch (InterruptedException e) {}
}
}
}

Immutable Object:
就像final 的变量,可以不用synchronized, 设计成不可变的Object,也可以不需要synchronized。而Immutable需要遵循:
1. 没有setter,
2. 所有字段,final private
3. 不允许子类,override 字段, 最简单 就是 final 类(不允许继承), 或者使用单例模式
4. 如果保护可变对象的引用,不允许她们更改,首先在内部的方法中不改变它们,其次最好不要共享这个对象,创建对象的副本,保存这个副本
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值