一、对于synchronized:
使用环境:多线程的同步机制对资源加锁,使得只有一个线程可以操作,同步用于解决多线程同时访问某一个资源出现的问题。同步机制使用synchronized关键字实现。
用法:
1. 修饰一个方法,这个方法就叫做同步方法。但是,同步加锁的是对象,而不是代码。
class Book extends Thread
{
private int id;
public Book(int v)
{
id = v;
}
public synchronized void Print(int v)
{
while(true)
System.out.println(v);
}
public void run()
{
Print(id);
}
}
public class SyncTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Book b1 = new Book(0);
b1.start();
Book b2 = new Book(1);
b2.start();
}
}
输出结果:两本书b1,b2各自运行输出,互不影响。说明b1,b2两个实例都拿到了对自己的使用权,即synchronized关键字此处是对类的实例对象加锁。
2. 对一个资源加锁,synchronized(object)的用法,同步加锁的针对当前对象的object。
class Book extends Thread {
private int count=0;
private int id;
public Book(int v) {
id = v;
}
public void printVal(int v) {
synchronized(Book.class) {
while(count++<=10)
System.out.println(v);
}
}
public void run() {
printVal(id);
}
}
public class SyncTest {
public static void main(String[] args) {
Book b1 = new Book(0);
b1.start();
Book b2 = new Book(1);
b2.start();
}
}
输出结果:先输出b1的0,再输出b2的1。说明此时是对类上锁,b1先拿到了类Book的使用权,之后b2才拿到,即synchronized此时对synchronized(object)的object上锁。
上面的例子有个缺点,用到同步就希望将性能的损失降到最低,因为同步的资源“越大”,损失的性能就越多,再看上面的例子是对整个类加锁,粒度太大,换一种思路,如果我们对类中的静态变量(static)加锁,由于静态变量是全局的,所有类的实例共用它,也可以达到上面的目的。
也就是说,在达到同样目的的时候,我们要尽量控制synchronized(object)中object的大小。
class Book extends Thread {
private int count=0;
private int id;
private static Object lock=new Object();
public Book(int v) {
id = v;
}
public void printVal(int v) {
synchronized(lock) {
while(count++<=10)
System.out.println(v);
}
}
public void run() {
printVal(id);
}
}
public class SyncTest {
public static void main(String[] args) {
Book f1 = new Book(0);
f1.start();
Book f2 = new Book(1);
f2.start();
}
}
3. 对
一个方法中的一个区块加锁,synchronized(this){ /* block */ },表示只对这个区块的资源实行互斥访问,它的作用域是当前对象。
注意:
(1). 当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
(2). 当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。可以这么理解,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
4. synchronized关键字是不能继承的,也就是说,基类的方法synchronized method(){} 在继承类中并不自动是synchronized method(){},而是变成了method(){}。继承类需要你显式的指定它的某个方法为synchronized方法。
二、对于join:
join用于主线程等待子线程运行完毕它的run方法,再继续执行下面的代码。例如:
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(); //t1线程完成run方法后才会继续执行下面的代码!
t2.start();
t2.join();
}
}
class ThreadTesterA implements Runnable{
private int i;
@Override
public void run() {
// TODO Auto-generated method stub
while(i<10){
System.out.print("i="+i+" ");
i++;
}
System.out.println();
}
}
class ThreadTesterB implements Runnable{
private int j;
@Override
public void run() {
// TODO Auto-generated method stub
while(j<10){
System.out.print("j="+j+" ");
j++;
}
System.out.println();
}
}