多线程

一、什么是线程?

线程是一个进程(应用程序)中的执行场景。一个进程可以启动多个线程。多线程并发执行可以提高程序的效率, 可以同时完成多项工作。

二、多线程的作用?

多线程不是为了提高执行速度,而是提高应用程序的使用率。
线程和线程共享“堆内存和方法区内存”,栈内存是独立的,一个线程一个栈。
可以给现实世界中的人类一种错觉:感觉多个线程在同时执行。

三、实现

1)继承Thread类

public class MyThread extends Thread{
    public void run(){       //重写
}
MyThread  myThread=new MyThread ();
myThread.start();   //start()使该线程开始执行,JVM调用run()
//匿名内部类
    new Thread(){          //继承Thread类
        public void run(){
        }
    }.start();

2)实现Runnable接口

public class MyThread implements Runnable{
    public void run(){
     }
}
MyThread  myThread=new MyThread ();
Thread thread=new Thread(myThread);
thread.start();
//匿名内部类 
    new Thread(new Runnable(){          //实现Runnable接口
          public void run(){
           }
    }).start();

3)实现Callable接口 (有返回值Future)

public interface Callable<V>   { 
  V call() throws Exception;   
} 
public class SomeCallable<V> extends OtherClass implements Callable<V> {

    @Override
    public V call() throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

}

Callable<V> oneCallable = new SomeCallable<V>();   
//由Callable<Integer>创建一个FutureTask<Integer>对象:   
FutureTask<V> oneTask = new FutureTask<V>(oneCallable);   
//注释:FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和Runnable接口。 
//由FutureTask<Integer>创建一个Thread对象:   
Thread oneThread = new Thread(oneTask);   
oneThread.start();   
//至此,一个线程就创建完成了。

四、什么是线程池?

事先将多个线程放入一个容器,需要的时候去取,而不用new。根据系统环境,配置线程的数量,达到最佳运行效果。

五、为什么使用线程池?

  • 降低资源损耗。减少线程的创建和销毁,每个工作线程重复利用。
  • 减少响应时间。任务到达时,任务不用等待线程创建就可执行。
  • 提高线程的可管理性。线程时稀缺资源,无限制的创建,会消耗系统资源,还会降低系统稳定性,使用线程池可以进行统一管理调配。

六、线程相关方法

  • object.wait() :会导致线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
  • object.notify() :唤醒等待的线程,这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用
  • thread.join():当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续
  • Thread.currentThread():获取当前线程的对象.
  • Thread.sleep(毫秒,纳秒):休眠线程.
    sleep和wait的区别:
    sleep方法在同步方法或同步代码块中,不释放锁
    wait方法在同步方法或同步代码块中,释放锁
    1,这两个方法来自不同的类分别是Thread和Object
    2,最主要是sleep方法没有释放锁,而wait方法释放了锁,使得敏感词线程可以使用同步控制块或者方法。
    3,wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在
    任何地方使用
    synchronized(x){
    x.notify()
    //或者wait()
    }
    4,sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常

七、同步synchronized

synchronized 修饰方法时锁定的是调用该方法的对象。它并不能使调用该方法的多个对象在执行顺序上互斥
1)同步代码块

//使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块
//多个同步代码块如果使用相同的锁对象, 那么他们就是同步的
class XX{
		Demo d = new Demo();
		public static void print1() {
			synchronized(d){				//锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
					   //
			}
		}
		public static void print2() {	
			synchronized(d){	
                      //
			}
		}
}

2)同步方法

//使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的

class XX{
		public static void print1() {
			synchronized(Printer.class){	//锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
                    //
			}
		 }
		/*
		 * 非静态同步函数的锁是:this
		 * 静态的同步函数的锁是:字节码对象
		 */
		 public static synchronized void print2() {	
                    //
		}
}

八、线程安全

多线程并发操作同一数据时, 就有可能出现线程安全问题,使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作
Vector是线程安全的,ArrayList是线程不安全的
StringBuffer是线程安全的,StringBuilder是线程不安全的
Hashtable是线程安全的,HashMap是线程不安全的

九、ThreadLocal

ThreadLocal类为每一个线程都维护了自己独有的变量拷贝。每个线程都拥有了自己独立的一个变量。
ThreadLocal是采用哈希表的方式来为每个线程都提供一个变量的副本
ThreadLocal保证各个线程间数据安全,每个线程的数据不会被另外线程访问和破坏

十、线程的五个状态

创建、就绪、运行、阻塞、死亡

posted @ 2018-06-10 17:56  Steph_Chen  阅读(132)  评论(0编辑  收藏  举报