第一次写博客 2016.4.18
并发肯定就需要用到java的多线程了,首先得清楚就算没用上多线程就只简单写个hello world,事实上jvm就已经自动创建了一个main thread了:System.out.println(Thread.currentThread().getName());
自己创建线程的两种方法:
一般第一种,传入一个Runnable的借口实现类,在run方法中应该写这个线程的task代码
Thread t = new Thread(new Runnable(){
@Override
public void run() {
// do work;
}
});
t.start();
第二种需要继承Thread,损失了扩展性。
class Test1 extends Thread {
Test1() {
}
@Override
public void run() {
// do work;
}
public static void main(String[] args) {
new Test1().start();
}
}
多个线程并发地读写同一个资源会产生不可预测的错误,所以我们需要让多个线程安全地访问同一个资源,所以有了同步。synchronized。
public class Test implements Runnable {
Source source;
Test(Source source) {
this.source = source;
}
public static void main(String[] args) {
Source source = new Source();
System.out.println("hello zxisl");
System.out.println(Thread.currentThread().getName());
Thread t = new Thread(new Test(source));
t.start();
new Test1(source).start();
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + source.work());
}
}
}
class Test1 extends Thread {
Source source;
Test1(Source source) {
this.source = source;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + source.work());
}
}
}
class Source {
private int i;
public int work() {
synchronized (this) {//假如i代表第i张火车票两个线程代表两个售票窗口,如果不同步,同一张火车票可能被卖出两次。
i++;
try {
Thread.sleep(50);//为了让效果明显
} catch (InterruptedException e) {
e.printStackTrace();
}
return i;
}
}
}
synchronized (this) 对象同步。
synchronized (className.class) 类同步。
具体不写了。
这里有一个疑问 假如一个类中两个方法有同步锁,一个被锁定的时候影响另一个同步方法么?有时间去测试一下。
5.0之后 java.util.concurrent 并发包里还提供了强大的同步锁lock。
public class Testlock {
static int i;
static Lock lock = new ReentrantLock();
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
// lock.lock(); //lock与unlock之间的代码等同于synchronized代码快。
Testlock.i++;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + Testlock.i);
// lock.unlock();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
// lock.lock();
Testlock.i++;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + Testlock.i);
// lock.unlock();
}
}
}).start();
}
}
concurrent包里面的其它:
ReadWriteLock
内置两个Lock,一个是读的Lock,一个是写的Lock。
* 多个线程可同时得到读的Lock,但只有一个线程能得到写的Lock,
* 而且写的Lock被锁定后,任何线程都不能得到Lock。ReadWriteLock提供的方法有:
* readLock(): 返回一个读的lock
* writeLock(): 返回一个写的lock, 此lock是排他的。
* ReadWriteLockTest很适合处理类似文件的读写操作。
* 读的时候可以同时读,但不能写;写的时候既不能同时写也不能读。
CyclicBarrier
允许一组线程互相等待,直到到达某个公共屏障点。
CyclicBarrier(int,Runnable);//当await的数量到达了设定的数量后,首先执行该Runnable对象。
await(); //通知barrier已完成线程
Semaphore
运行规定多个线程并发访问资源。信号量机制, 当每个线程获得资源,信号量-1,当前信号量为0,必须阻塞等待其他线程释放资源。
Exchanger
可以在两个线程之间交换数据,只能是2个线程。当线程A调用Exchange对象的exchange()方法后,他会陷入阻塞状态,直到线程B也调用了exchange()方法,然后以线程安全的方式交换数据,之后线程A和B继续运行。