线程:进程内部的一个执行序列。
进程:执行着的应用程序。
线程的名字:
1、每一个线程都有自己的名字。
main线程的名字就是main,其它线程名字默认:Thread-0,Thread-1...
2、线程名字的获取:getName().
3、线程名字的修改
1)、setName(String name);
2)、可以在new线程的时候,构造方法里面给出线程名
4、当前线程的获取
JVM开启主线程,运行方法main,主线程也是线程,是线程必然是Thread类对象,
Thread类中,静态方法:static Thread currentThread()返回正在执行的线程对象
Thread t = Thread.currentThread();
线程创建的三种方法:
1、继承Thread类,重写run()方法。
2、实现Runnable接口,重写run()方法。
3、用Executer框架来创建线程池。
注:推荐使用实现Runnable,和线程池来创建线程。因为Java只能单继承,但是可以多实现,线程池可以更方便的创建多个线程。
继承Thread和实现Runnable创建线程:
//继承Threadpublic class Demo extends Thread{
public void run(){
for(int i = 0;i < 50; i++){
System.out.println("Thread " + i);
}
}
}
//实现Runnable
public class SunRunnable implements Runnable{
public void run() {
for(int i = 0;i < 50; i++){
System.out.println("Runnable "+i);
}
}
}
使用线程池创建线程:
//使用线程池来创建线程public class ThreadPool { public static void main(String[] args) { //调用工厂类的静态方法,创建线程池对象 //返回线程池对象,是返回的接口 ExecutorService es = Executors.newFixedThreadPool(2); //调用接口实现类对象es中的方法submit提交线程任务 //将Runnable接口实现类对象,传递 es.submit(new ThreadPoolRunnable()); //关闭线程池 es.shutdown(); }}public class ThreadPoolRunnable implements Runnable{ public void run() { System.out.println("线程提交的任务!!!"); }}//线程池,实现Callable接口方式public class ThreadPoolDemo1 { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService es = Executors.newFixedThreadPool(2); //提交线程任务的方法submit方法返回Future接口的实现类 Future<String> f = es.submit(new ThreadPoolCallable()); String s = f.get(); System.out.println(s); //关闭线程 es.shutdown(); }}public class ThreadPoolCallable implements Callable<String>{ @Override public String call() throws Exception { return "abc"; }}//程序运行结果 abc
线程安全问题:
1、多线程在同时执行,并且有共享资源的时候会发生。(比如在买票的时候,总票数是一定的,一个线程在卖票在一半的时候,CUP把线程给了另一个卖票的,而这一个票已经被第一个线程卖出去了)
2、线程安全问题说到底是因为多线程在同时执行的时候,由于CUP不定时的分配导致线程执行紊乱。只要让多线程在执行的时候,让每一个线程都能执行完自己的这一段代码就可以了。
3、Java对线程安全提出了解决办法。 synchronized 关键字,可以实现同步锁,当这个线程代码没执行完,就不让别的线程进来。
线程锁:
1、synchronized:可以构造同步方法,也可以构造同步代码块(构造同步代码块的时候,需要同步锁,这个同步锁可以是任何对象,但必须是唯一的,它的作用是一把钥匙)
注:当使用的是同步方法的时候,同步锁是 this
2、lock:它的作用是构造同步代码块,不需要同步锁,lock() 获取锁,unlock()释放锁,在获取锁和释放锁之间形成同步代码块。(它需要一个Lock对象来调用,可以new一个)
代码展示这两种解决线程安全问题:
//synchronizedpublic class ThreadDemo { public static void main(String[] args) { //创建Runnable接口实现类 Tickets t = new Tickets(); //创建三个Thread类对象,传递Runnable接口实现类 Thread t0 = new Thread(t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t0.start(); t1.start(); t2.start(); }}public class Tickets implements Runnable{ //定义可以出售的票张数 private int ticket = 100; private Object obj = new Object(); public void run() { while(true){ //线程共享数据,保证安全,加入同步代码块 synchronized(obj){ //对票进行判断 if(ticket > 0){ System.out.println(Thread.currentThread().getName() + "出售第" + ticket-- + "张!!!"); } } } }}//lockpublic class ThreadDemo { public static void main(String[] args) { //创建Runnable接口实现类 Tickets t = new Tickets(); //创建三个Thread类对象,传递Runnable接口实现类 Thread t0 = new Thread(t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t0.start(); t1.start(); t2.start(); }}public class Tickets implements Runnable{ //定义可以出售的票张数 private int ticket = 100; //在类的成员位置,创建Lock接口的实现类对象 private Lock lock = new ReentrantLock(); public void run() { while(true){ //调用Lock接口方法lock获取锁 lock.lock(); if(ticket > 0){ System.out.println(Thread.currentThread().getName() + "出售第" + ticket-- + "张!!!"); } //释放锁, lock.unlock(); } }}
死锁:两个进程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是两个进程 都陷入了无限的等待中。
线程等待和唤醒(notify,wait):
1、当需要一个线程完全执行完才能执行下一个线程的时候。(同步锁:是这个线程的代码块不执行完不会再次执行这个代码块)
2、这个时候要用到线程等待和唤醒,当一个线程没执行完的时候,让另一个线程等待。当上一个线程执行完后,在去唤醒这个线程。
注:用sleep让线程睡眠,如果是多线程的话,CUP不会在此等待休眠结束,而是去执行别的线程。