多线程相关,线程池,定时器

来源:互联网 发布:网络培训考试软件下载 编辑:程序博客网 时间:2024/05/22 12:01

进程:正在运行的程序,是系统进行资源分配和调用的独立单位,每一个进程都有它自己的内存空间和系统资源

线程:进程里面的执行路径,线程依赖进程而存在。

进程很多但是核心很少?因为cpu在进行高速切换

多进程不是提高执行速度,而是提高cpu使用率。多线程,提高应用程序的使用率,cpu在使用程序

并行:时间段上来说多个程序运行

并发:时间点上来说程序运行,多个cpu实现程序的并发

一个程序至少一个进程,一个进程至少一个线程。线程依托进程存在。

jvm虚拟机启动是单线程还是多线程?        多线程

每个线程都有优先级

创建线程的方法有两种

1️⃣将类声明为Thread的子类,该子类重写Thread类的run方法,

线程中start和run的区别

start是使线程开始执行,java虚拟机调用该线程的run方法

run是对象调用方法,还是主线程在进行操作

public class ThreadDemo {public static void main(String[] args) {MyThread thread = new MyThread();//thread.run();thread.start();System.out.println("over");}}class MyThread extends Thread{public void run(){try {sleep(500);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}for (int i = 0; i < 10; i++) {System.out.println(i);}}}
创建新线程并沉睡500ms,此时后面的system.out已经执行了(正经的start才会出现这种情况)

线程不能多次启动,会出现报错

Exception in thread "main" java.lang.IllegalThreadStateException



getName()          默认thread-0  获取线程名字

setName(String name) 设置线程名字

获取主线程对象

Thread thread2 = Thread.currentThread();System.out.println(thread2.getName());

线程的阻塞方法的使用

join方法:等待线程运行完之后再运行。括号中还可以加时间,超过最大等待时间就开始运行

public class TestJoin {   public static void main(String[] args) {       MyThread2 t1 = new MyThread2("TestJoin");    t1.start();    try {      t1.join();  //join()合并线程,子线程运行完之后,主线程才开始执行     }catch (InterruptedException e) {  }           for(int i=0 ; i <10; i++)              System.out.println("I am Main Thread");   } }  class MyThread2 extends Thread {      MyThread2(String s) {     super(s);     }       public void run() {    for(int i = 1; i <= 10; i++) {     System.out.println("I am "+getName());     try {      sleep(1000); //暂停,每一秒输出一次      }catch (InterruptedException e) {      return;     }     }   }  }


输出结果
I am TestJoinI am TestJoinI am TestJoinI am TestJoinI am TestJoinI am TestJoinI am TestJoinI am TestJoinI am TestJoinI am TestJoinI am Main ThreadI am Main ThreadI am Main ThreadI am Main ThreadI am Main ThreadI am Main ThreadI am Main ThreadI am Main ThreadI am Main ThreadI am Main Thread

yield()方法:暂停当前正在执行的线程对象,并执行其他线程


stop()方法已经过时

现在停止线程所用方法是使用标签

public class ThreadDemo3 {public static void main(String[] args) {Thread3 t = new Thread3();t.start();t.run();}}class Thread3 extends Thread{private boolean flag;public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;}@Overridepublic void run() {for (int i = 0; i < 1000; i++) {if(i==3){flag=false;}if(!flag){return;}System.out.println(i);}}}

command+option+s添加set和get。符合停止条件时改变flag的值来实现让线程停止。

线程中断方法

interrupt():打破阻塞状态,中断线程,还会返回interruptException错误


配合join()的线程中断方法

//线程中断方法,配合join()public class ThreadDemo4 {public static void main(String[] args) {// TODO Auto-generated method stub// 通过构造方法将主线程对象传递给子线程Thread4 t = new Thread4(Thread.currentThread());t.start();try {t.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}// Thread.currentThread().interrupt();//放在这里无意义System.out.println("over");}}class Thread4 extends Thread {private Thread mainThread;public Thread4(Thread mainThread) {this.mainThread = mainThread;}@Overridepublic void run() {// 让主线程阻塞之后,再执行try {Thread.sleep(500);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}for (int i = 0; i < 10; i++) {// 当i3的时候,中断线程if (i == 3) {mainThread.interrupt();}System.out.println(i);}}}


配合sleep()的线程中断方法

public class ThreadDemo5 {public static void main(String[] args) {Thread5 t = new Thread5();t.start();try {Thread.sleep(500);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}t.interrupt();System.out.println("over");}}class Thread5 extends Thread {public void run() {try {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}for (int i = 0; i < 10; i++) {System.out.println(i);}}}

线程的生命周期

线程先start启动,因为没有cpu执行权,所以没有执行资格,抢到cpu执行权,调用线程的方法,此时run,stop会线程执行结束,sleep,join,wait会进入阻塞状态,等待cpu


2️⃣创建线程的另一种方式是声明实现Runnable()接口的类,该类实现run方法,然后可以分配该类的实例,在创建thread的时候作为一个参数来传递并启动。

多线程可以执行一个Runnable任务

public class ThreadDemo6 {public static void main(String[] args) {// TODO Auto-generated method stubMyRunnable task = new MyRunnable();//多个线程执行同一个Runnable任务new Thread(task).start();new Thread(task).start();}}class MyRunnable implements Runnable{private int count=10;@Overridepublic void run() {// TODO Auto-generated method stubwhile(count>0){System.out.println(count);count--;}}}

有资源共享,就用Runable方法


多线程的线程安全问题及同步代码块,同步方法相关

出现线程安全问题的原因?

多线程环境下且存在共享数据,同时共享数据被多条语句引用

解决线程安全问题的方法?

让操作共享数据的代码在任意时间只能被同一个线程所操作

可以使用同步代码块实现:synchronized(锁对象){

存在线程安全的代码

 }

同步代码块的优缺点

优点:解决了线程安全问题

缺点:每次运行的时候都要检查锁对象是否被释放

同步方法:

在run方法前面修饰符加上synchronized,将整个方法的代码都锁起来

非静态同步方法的锁对象又是什么呢?

this

静态方法的锁对象是:当前类的字节码文件对象

锁对象:锁对象可以是任意对象,多个线程必须使用的是同一把锁,也就是说必须使用同一个对象

锁对象什么时候会释放?

同步代码执行完毕

线程进入等待状态

线程停止


什么时候使用同步代码块,什么时候使用同步方法?

当方法里面只有一部分代码存在安全问题时候,使用同步代码块

当方法里面所有的代码都存在安全问题的时候切当前锁对象可以this时使用同步方法





实现Runnnable接口的创建线程可以使用同步代码块和同步方法

继承Thread类的创建线程只能使用同步代码块,不能使用同步方法

售票程序

public class ThreadTest {public static void main(String[] args) {/* * 线程同步安全问题出现的根据: 多线程环境 多线程操作共享数据 操作数据的语句是多行 * 线程安全问题的解决方法:让操作共享数据的代码在同一时间只能被同一个线程所操作 */// 集成Thread方式// TicketThread t = new TicketThread("窗口1");// t.start();// TicketThread t2 = new TicketThread("窗口2");// t2.start();// TicketThread t3 = new TicketThread("窗口3");// t3.start();// 实现Runnable接口的方式TicketRunnable ticket = new TicketRunnable();new Thread(ticket, "窗口1").start();new Thread(ticket, "窗口2").start();new Thread(ticket, "窗口3").start();}}

继承Thread类

public class TicketThread extends Thread {// 所有进程共享资源是票,必须加staticprivate static int ticket = 100;public TicketThread(String name) {// TODO Auto-generated constructor stubsuper(name);}@Overridepublic void run() {synchronized (Object.class) {while (ticket > 0) {System.out.println(getName() + "正在出售第" + ticket + "张票");ticket--;}}}}

实现Runnable接口

public class TicketRunnable implements Runnable {private int ticket = 100;@Overridepublic void run() {// TODO Auto-generated method stubwhile (ticket > 0) {System.out.println(Thread.currentThread().getName() + "正在出售第" + ticket + "张票");ticket--;try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}



火车进站小程序

线程方法:

public final void wait()使线程等待

public final void notify()随机唤醒等待的其中一个线程

public final void notifyAll()唤醒所有等待中的线程

public void interrupt()可以中断等待的线程状态


!!!!上述方法必须在同步代码里面通过锁对象调用object.class.调用

为什么定义在object类中?

因为锁对象可以是任意对象,又因为wait,notify,notifyAll必须通过锁对象调用,即任意对象都可以调用这些方法,同时又因为任意对象都可以调用的方法应该定义在Object类中,所以定义在Object类中。

public class EnterTrainDemo {public static void main(String[] args) {EnterTrainRunnable passenger = new EnterTrainRunnable();new Thread(passenger,"乘客1").start();new Thread(passenger,"乘客2").start();new Thread(passenger,"乘客3").start();new Thread(passenger,"乘客4").start();//等到乘客都进站了,进站之后再唤醒乘客try {Thread.sleep(50);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}passenger.setOpen(123456);new Thread(passenger,"工作人员").start();}}class EnterTrainRunnable implements Runnable{private boolean isOpen;public void setOpen(int key){if(key==123456){isOpen=true;}}@Overridepublic void run() {// TODO Auto-generated method stubsynchronized (Object.class) {if(isOpen){isOpen=false;System.out.println(getThreadName()+"进站了,5秒钟后放行乘客");try {Thread.sleep(500);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//Object.class.notify();//随机唤醒一个乘客Object.class.notifyAll();}else{System.out.println(getThreadName()+"正在等待");try {Object.class.wait();//线程进入等待状态,锁对象会释放} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(getThreadName()+"被放行了");}}}private String getThreadName() {// TODO Auto-generated method stubreturn Thread.currentThread().getName();}}

关于锁Lock

public class TicketRunnable implements Runnable {private int ticket = 100;private Lock lock=new ReentrantLock();@Overridepublic void run() {// TODO Auto-generated method stublock.lock();while (ticket > 0) {System.out.println(Thread.currentThread().getName() + "正在出售第" + ticket + "张票");ticket--;try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}lock.unlock();}}

尽量多个线程使用同一把锁,可以避免死锁。




线程池:为了防止频繁创建销毁线程浪费系统资源而创建的线程容器

全是静态成员方法,是个工具类。

从JDK1.5之后,java内置线程池

三种创建线程池的方法

1️⃣创建一个存活60s的线程池

ExecutorService threadPool = Executors.newCachedThreadPool();threadPool.execute(myRunnable);

2️⃣创建一个只放一个线程的线程池

ExecutorService threadPool = Executors.newSingleThreadExecutor();threadPool.execute(myRunnable);

3️⃣创建一个指定线程数的线程池

ExecutorService threadPool = Executors.newFixedThreadPool(3)threadPool.execute(myRunnable);
线程池的关闭

threadPool.shutdown()



自定义线程池工具类

public class ThreadPoolUtils {public static void execute(Runnable task) {private static ExecutorService threadPool = Executors.newCachedThreadPool();public static void execute(Runnable task){threadPool.execute(task);}}}

匿名内部类创建线程的两种方式

public class ThreadDemo {public static void main(String[] args) {// TODO Auto-generated method stubnew Thread(){@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(i);}}}.start();new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stub}}).start();}}class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(i);}}}class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(i);}}}

线程的定时器:可用于调度多个定时任务以后台线程的方式执行。可安排任务执行一次,或者定期重复执行

public class TimerDemo {public static void main(String[] args) {//创建一个新的定时器Timer timer = new Timer();//要被执行的任务MyTimerTask mytimerTask = new MyTimerTask();//安排在制定延迟后执行指定任务,多长时间之后任务开始执行,执行之后每隔多久开始执行下一个timer.schedule(mytimerTask, 1000,1000);timer.cancel();}}class MyTimerTask extends TimerTask{@Overridepublic void run() {SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println(format.format(new Date()));//当任务执行完毕之后,关闭定时器}}

同步有三种方式

同步代码块:锁对象可以使任意对象,所以用object。

同步方法:锁对象是this,关键字放在方法的修饰符位置上

使用lock子类对象:创建ReentrantLock子类对象然后使用lock和unlock分别进行加锁和解锁。

run()和start()的区别

run()没有创建新的线程。start()创建了新的线程。

sleep()和wait()方法的区别?

sleep是睡眠指定时间,等指定时间到了就苏醒

wait:只能在同步代码中通过锁对象调用,必须通过锁对象唤醒。

原创粉丝点击