多线程运行的原理:每个程序就是进程,而每个进程中会有多个线程,而CPU是在这个写线程之间进行切换,多线程可以提高程序的运行效率,但是不能无限制的开线程。

Thread种run()方法和start()方法的区别:

run()方法只是普通方法的调用,不会新的线程,start()则会开启一个新的线程。

一、synchronized 线程同步锁
synchronized是java中的一个关键字,也就是说是java语言内置的特性。

如果一个代码块被synchronized 修饰了,当一个线程获取了对应的锁(同一把锁,synchronized中的参数相同就是同一把锁),并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况: 

1.获取锁的线程执行完了该代码块,然后线程释放对锁的占有。

2.线程执行发生异常,此时JVM会让线程自动释放锁。

final MySynchronized mySynchronized = new MySynchronized();
 
final MySynchronized mySynchronized2 = new MySynchronized();
 
new Thread(){
 
public void run() {
 
synchronized (mySynchronized) { //可以传任意对象,相同的就是同一把锁
 
System.out.println(this.getName() + "---start---");
 
try {
 
Thread.sleep(5000);
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
}
 
System.out.println(this.getName() + "---end---");
 
}
 
}
 
}.start();

 二、Lock锁
Lock和 synchronized的区别:

1)、Lock不是java语言内置的, synchronized是java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问。

2)、Lock和 synchronized一个非常大的不同就是, synchronized不需要用户去手动释放锁,当 synchronized方法或者 synchronized代码块执行完毕后或者在发生异常时候,系统会自动让线程释放对锁的占用;而lock必须要用户去手动释放锁,就有可能导致出现死锁现象,因此使用Lock时需要在finally块中释放锁。(使用Lock一定要在try{}catch{}块中进行,在finally去释放锁unlock,否则在发生异常的时候,会造成死锁)。

3)、Lock可以让等待的线程相应中断,而synchronized去不行,使用synchronized时,等待的线程会一直等待下去,不能都响应中断;

4)、Lock可以知道有没有成功获取锁,而synchronized却无法办到。

5)、Lock可以提高多个线程进行读操作的效率。

在性能上来说,如果竞争资源不激烈,两者的性能是差不多,而当竞争资源非常激烈时(即有大量的线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。

Lock是java.util.concurrent.locks包下的类

Lock是一个接口

public interface Lock{
 void lock(); //获取锁void lockInterruptibly throws interruptedException; //获取可中断的锁(这里是指等待的线程可以不在等待)
boolean tryLock(); //试着获取锁,返回true或false
boolean tryLock(long time,TimeUnit unit) throws InterruptedException; //如果没有拿到锁,会等一定时间
void unlock(); //释放锁
}

1.lockInterruptibly()//可中断锁
lockInterruptibly()方法,当线程通过这个方法去获取锁时,如果其他线程正在等待获取锁,则这个等待的线程可以被中断等待的状态。也就是说,当两天线程同时通过lock.lockInterruptibly()方法想获取某个锁时,假若此时A线程获取了锁,而线程B只有等待,那么线程B可以调用threadB.interrupt()方法能够中断线程B 的等待状态。(注意是等待的线程的等待状态被中断,获取锁的线程不会被中断)

例子:

public class MyInterruptibly {
    private Lock lock = new ReentrantLock();
 
    public static void main(String[] args) {
        MyInterruptibly test = new MyInterruptibly();
        MyThread thread0 = new MyThread(test);
        MyThread thread1 = new MyThread(test);
        thread0.start();
        thread1.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread1.interrupt();
        System.out.println("================================");
    }
 
    public void insert(Thread thread) throws InterruptedException{
        lock.lockInterruptibly();
      try {
    System.out.println(thread.getName() + "得到了锁");
    long startTime = System.currentTimeMillis();
    for (; ; ) {
        if (System.currentTimeMillis() - startTime >= Integer.MAX_VALUE)
            break;
    }
}finally {  //防止异常出现死锁
    lock.unlock();
    System.out.println(thread.getName()+"释放了锁");
}
 
 
}
class MyThread extends Thread{
    private MyInterruptibly test = null;
    public MyThread(MyInterruptibly test){
        this.test = test;
    }
    public void run(){
        try {
            test.insert(Thread.currentThread());
        } catch (Exception e) {
            // e.printStackTrace();
            System.out.println(Thread.currentThread().getName()+"被中断");
        }
    }
}

2.tryLock
tryLock(long time,TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁的时候会等待一定时间,在时间期限内如果还拿不到锁,就返回false.如果一开始就拿到锁或者在等待期限内拿到了锁,则返回true。

public class MyTryLock {
    private static ArrayList<Integer> arrayList = new ArrayList<Integer>();
    static Lock lock = new ReentrantLock();
 
    public static void main(String[] args) {
        new Thread(){
            public void run(){
                Thread thread  = Thread.currentThread();
                boolean tryLock = lock.tryLock();
                System.out.println(thread.getName()+" "+tryLock);
                if(tryLock){
                    System.out.println(thread.getName() + "拿到了锁");
                    for(int i = 1;i<10;i++){
                        arrayList.add(i);
                    }
                    lock.unlock();
                    System.out.println(thread.getName()+"释放了锁");
                }
            }
        }.start();
        new Thread(){
            public void run(){
                Thread thread  = Thread.currentThread();
                boolean tryLock = lock.tryLock();
                System.out.println(thread.getName()+" "+tryLock);
                if(tryLock){
                    System.out.println(thread.getName() + "拿到了锁");
                    for(int i = 0;i<10;i++){
                        arrayList.add(i);
                    }
                    lock.unlock();
                    System.out.println(thread.getName()+"释放了锁");
                }
            }
        }.start();
    }
 
}

3.ReadWriteLock读写锁
ReadWriteLock也是一个接口,在它里面只定义了两个方法:

public interface ReadWriteLock(){
Lock readLock();

Lock writeLock();

}

一个用来获取读锁,一个用户来获取写锁,也就是说将文件的读写操作分开,分成2个锁来分配线程,从而使得多个线程可以同时进行读操作。下面的ReentranReadWriteLock实现了ReadWriteLock接口。

如果一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁,而其他申请线程如果要申请读锁则可以正常执行。

如果一个线程已经占用了写锁,则此时其他线程如果申请写锁或读锁,则申请的线程会一直等待释放写锁。

ReadWriteLock读写锁和synchronized区别:

使用读写锁,可以实现读写分离锁定,读操作并发进行,写操作锁定单个进程。而使用synchronized则要读写都完成后才能释放锁。

public class MyReentranReadWriteLock {
    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    public static void main(String[] args) {
        final MyReentranReadWriteLock test = new MyReentranReadWriteLock();
        new Thread(){
            public void run(){
                test.get(Thread.currentThread());
                test.write(Thread.currentThread());
            }
        }.start();
        new Thread(){
            public void run(){
                test.get(Thread.currentThread());
                test.write(Thread.currentThread());
            }
        }.start();
    }

    //读操作,用读锁来锁定
 

public void get(Thread thread){
        rwl.readLock().lock();
        try {
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() -start <= 1){
                System.out.println(thread.getName()+"正在进行读操作");
            }
            System.out.println(thread.getName()+"读操作完毕");
        }finally {
            rwl.readLock().unlock();
        }
    }
    //写操作用写锁来锁定
    public void write(Thread thread){
        rwl.writeLock().lock();
        try {
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() - start <=1){
                System.out.println(thread.getName()+"正在进行写操作");
            }
            System.out.println(thread.getName()+"写操作完毕");
        }finally {
            rwl.writeLock().unlock();
        }
    }
}