目录 1、什么是进程?什么是线程? 进程是一个应用程序,线程是一个进程中的执行场景/执行单元。一个进程可以启动多个线程。在java语言中对于两个线程A和B,堆内存和方法区内存共享。但是栈内存独立,一个线程一个栈。 在使用了多线程机制之后,main()方法结束了,只是主线程结束了,主栈空了,但其他线程不一定结束,其他栈(线程)可能还在压栈弹栈。 java语言支持多线程机制。并且java已经实现了多线程(java.lang.Thread类和java.lang.Runnable接口) 第一种实现方式(继承java.lang.Thread类并重写run方法) 第二种实现方式(实现java.lang.Runnable接口并实现run方法) 通常使用第二种方法,因为一个类实现了接口还可以继承其他类 注意:start方法和run方法的区别!!! run方法不会启动线程。 start方法的作用是:启动一个线程,在JVM中为线程开辟一个新的栈空间。之后start方法就结束了。线程启动成功并进入排队等待序列。等到被CPU调用到,就会自动调用run方法。
作用:让线程进入休眠,进入“阻塞状态”。放弃占有CPU时间片,让其他线程使用。 interrupt方法可以中断线程的睡眠,依靠了java异常处理机制 线程Thread_03_1原计划沉睡5秒,在它睡到3秒时,使用interrupt方法打断其睡眠。 stop方法可以强制终止一个线程的执行。不过这种方式容易丢失数据。因为这种方式会直接杀死线程,线程没有保存的数据会丢失。所以不建议使用 建议使用如下方法结束一个线程:在线程类中增加一个布尔类型的变量run,通过改变run的值,来控制线程运行/停止状态。 抢占式调度模型、均分式调度模型 最低优先级:1 默认优先级:5 最高优先级:10 优先级高的线程抢占的CPU时间片就多一些,处于运行状态的时间片就多一些 yield方法:使当前线程暂停,回到就绪状态,让给其他线程 join方法可以使得在t.join()中让CPU优先执行完t。将t合并到当前线程中,使当前线程受阻,t线程执行直到结束。 join()的底层实现代码。 join()是在底层调用了wait方法,当主线程调用了thread.join()之后,主线程进入此方法,调用join()方法中的wait(0)方法,wait(0)表示无限等待直到被notify。即主线程会无限等待thread线程执行完成。 数据在多线程并发的环境下会存在安全问题。例如如果多个用户想要修改某个共享的数据,就会引发线程安全问题。因此需要引入线程同步机制(即线程排队执行,不能并发) java里面通过关键字synchronized给线程加锁。线程会获取锁,并独占cpu,只有当线程释放了锁之后,其余线程拿到锁之后才能运行。 当一个线程在运行状态时遇到synchronized关键字,该线程就会放弃占有的cpu时间片,在锁池里面找共享对象的对象锁。 一个线程同步synchronized的例子——模拟ATM机取款 启动类:Test类 结果: 可以在实例方法上使用synchronized,synchronized出现在实例方法上,锁一定是this,不能是其他的对象了。所以这种方式不灵活。 另外还有一个缺点:synchronized出现在实例方法上,表示整个方法体都需要同步,可能会无故扩大同步的范围,导致程序的执行效率降低。所以这种方式不常用。 java中有三大变量 :1、实例变量(在堆中) 2、静态变量(在方法中) 3、局部变量(在栈中) 局部变量不会有线程安全问题,因为局部变量不共享,局部变量在栈中,一个线程一个栈。 常量不会有线程安全问题,因为常量不会被改变。 实例变量在堆中,堆只有1个。静态变量在方法区中,方法区只有1个。由于堆和方法区都是多线程可共享的,所以实例变量和静态变量可能存在线程安全问题。 ArrayList、HashMap 、HashSet 是非线程安全的 Vector、Hashtable 是线程安全的 synchronized有三种写法: 第一种:同步代码块(灵活) synchronized(线程共享对象){ 同步代码块; } 第二种:在实例方法上使用 synchronized 表示共享对象一定是this,并且同步代码块是整个方法体。 第三种:在静态方法上使用 synchronized 表示找类锁。 类锁永远只有1把(就算创建了100个对象,那类锁也只有1把) 对象锁:1个对象1把锁,100个对象100把锁。 类锁:100个对象,也可能只是1把类锁。 一个简单的死锁实现的例子 注:synchronized在开发中最好不要嵌套使用,一不小心就可能导致死锁现象发生 java语言中线程可分为两大类: 一类是:用户线程 例如:main方法主线程 一类是:守护线程(后台线程) 例如java垃圾回收线程 一般守护线程是一个死循环,所有用户线程只要结束,守护线程自动结束。 守护线程一般会用在一些定时任务,例如每天0点系统自动备份需要用到定时器,我们可以将定时器设置为守护线程一直在那里看着。每到0点就备份一次。所有的用户线程如果结束了,守护线程就自动退出。 使用Callable接口实现线程,可以获得该线程的返回值(JDK8新特性) 一个简单的实例: Future类中实现了get方法获取传入线程的返回结果 wait和notify方法不是线程对象的方法,不能通过线程对象调用。 一个简单的生产者和消费者实例 模拟生产者生产一个,消费者就消费一个。让仓库始终零库存。 :
线程基本概念
1、java实现线程
public class Thread_01 extends Thread { @Override public void run() { super.run(); System.out.println("第一个线程"); } public static void main(String[] args) { Thread thread=new Thread(new Thread_01(),"first_thread"); //创建线程对象 thread.start(); //启动线程 start方法使线程处于就绪队列,等待CPU调用 } }
public class Thread_02 implements Runnable { @Override public void run() { System.out.println("第一个线程"); } public static void main(String[] args) { Thread thread=new Thread(new Thread_01(),"first_thread"); //创建线程对象 thread.start(); //启动线程 start方法使线程处于就绪队列,等待CPU调用 } }
2、线程的生命周期
3、线程常用的方法
3.1、sleep()
public static native void sleep(long millis) throws InterruptedException;
public class Thread_03 { public static void main(String[] args) throws InterruptedException { Thread thread=new Thread(new Thread_03_1(),"Thread_03_1"); thread.start(); int count=1; //计数器 while(true){ System.out.println("Thread_03_1线程沉睡了"+count+++"秒"); Thread.sleep(1000); if(count>5){ break; } } } } class Thread_03_1 implements Runnable{ @Override public void run() { try { Thread.sleep(1000*5); //让线程沉睡(等待) 5秒 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } }
3.2、interrupt方法
public class Thread_03 { public static void main(String[] args) throws InterruptedException { Thread thread=new Thread(new Thread_03_1(),"Thread_03_1"); thread.start(); int count=1; //计数器 while(true){ System.out.println("Thread_03_1线程沉睡了"+count+++"秒"); Thread.sleep(1000); if(count==3){ System.out.println("打断Thread_03_1睡眠"); thread.interrupt(); break; } } } } class Thread_03_1 implements Runnable{ @Override public void run() { try { Thread.sleep(1000*5); //让线程沉睡(等待) 5秒 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"醒了"); } }
3.3、stop方法
public class Thread_04 { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Thread_04_1(), "Thread_03_1"); thread.start(); //线程Thread_03_1执行5秒后,强制结束线程Thread_03_1 Thread.sleep(1000*6); System.out.println("强制终止线程Thread_03_1"); thread.stop(); //强制终止线程 } } class Thread_04_1 implements Runnable{ @Override public void run() { for(int i=1;i<1000;i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread()+"-->"+i+"秒"); } } }
public class Thread_05 { public static void main(String[] args) throws InterruptedException { Thread_05_1 t=new Thread_05_1(); Thread thread = new Thread(t, "Thread_05_1"); thread.start(); //等候5秒之后,终止该线程 Thread.sleep(1000*5); t.run=false; System.out.println(thread.getName()+"线程已暂停"); } } class Thread_05_1 implements Runnable{ boolean run=true; //通过引入一个布尔类型的变量,来标记该线程的状态(运行/停止) @Override public void run() { for (int i = 1; i < 1000; i++) { if (run) { System.out.println(Thread.currentThread().getName() + "-->" + i + "秒"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }else{ /** * return就表示该线程结束了 * 如果有什么需要保存的,可以写在return之前 */ return; } } } }
4、线程调度
4.1、常见的线程调度模型
4.2、java中提供的线程调度方法
void setPriority(int newPriority) //设置线程优先级 int getPriority() //获取线程优先级
public class Thread_06 { public static void main(String[] args) { Thread_06_1 t61=new Thread_06_1(); Thread_06_2 t62=new Thread_06_2(); Thread_06_3 t63=new Thread_06_3(); Thread thread1=new Thread(t61,"Thread_06_1"); Thread thread2=new Thread(t62,"Thread_06_2"); Thread thread3=new Thread(t63,"Thread_06_3"); //设置线程优先级 thread1.setPriority(1); thread2.setPriority(2); thread3.setPriority(10); thread1.start(); thread2.start(); thread3.start(); System.out.println("主线程优先级为:"+Thread.currentThread().getPriority()); for(int i=0;i<1000;i++){ System.out.println(Thread.currentThread().getName()+"-->"+i); } } } class Thread_06_1 implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"优先级为:"+Thread.currentThread().getPriority()); for(int i=0;i<1000;i++){ System.out.println(Thread.currentThread().getName()+"-->"+i); } } } class Thread_06_2 implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"优先级为:"+Thread.currentThread().getPriority()); for(int i=0;i<1000;i++){ System.out.println(Thread.currentThread().getName()+"-->"+i); } } } class Thread_06_3 implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"优先级为:"+Thread.currentThread().getPriority()); for(int i=0;i<1000;i++){ System.out.println(Thread.currentThread().getName()+"-->"+i); } } }
4.3、线程让步
public static native void yield();
public class Thread_07 { public static void main(String[] args) { Thread_07_1 tt=new Thread_07_1(); Thread thread=new Thread(tt,"Thread_07_1"); thread.start(); for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"-->"+i); } } } class Thread_07_1 implements Runnable{ @Override public void run() { for(int i=0;i<100;i++){ if(i%10==0){ System.out.println(Thread.currentThread().getName()+"暂停了一下"); Thread.yield(); //让当前线程暂停一下 } System.out.println(Thread.currentThread().getName()+"-->"+i); } } }
4.4、线程合并
public class Thread_08 { public static void main(String[] args) throws InterruptedException { Thread_08_1 thread_08_1=new Thread_08_1(); Thread_08_2 thread_08_2=new Thread_08_2(); Thread thread=new Thread(thread_08_1,"Thread_08_1"); Thread thread1=new Thread(thread_08_2,"Thread_08_2"); thread.start(); //合并线程 thread.join(); //t合并到当前线程中,当前线程受阻塞,t线程执行直到结束 thread1.start(); thread1.join(); //Thread.currentThread().join(); System.out.println("main over"); } } class Thread_08_1 implements Runnable{ @Override public void run() { for(int i=0;i<3;i++){ System.out.println(Thread.currentThread().getName()+"-->"+i); } } } class Thread_08_2 implements Runnable{ @Override public void run() { for(int i=0;i<3;i++){ System.out.println(Thread.currentThread().getName()+"-->"+i); } } }
public final void join() throws InterruptedException { join(0); } public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
public final void wait(long timeout, int nanos) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); } if (nanos > 0) { timeout++; } wait(timeout); }
4.5、线程安全
4.5.1、线程同步的实现
Account类
package ATM; /* 银行账户,使用线程同步机制,解决线程安全问题 */ public class Account { private String accountName; //账户名 private double remain; //余额 Object obj=new Object(); public Account(String accountName, int remain) { this.accountName = accountName; this.remain = remain; } public String getAccountName() { return accountName; } public void setAccountName(String accountName) { this.accountName = accountName; } public double getRemain() { return remain; } public void setRemain(double remain) { this.remain = remain; } //取款方法 public void withdraw(double money) { //synchronized (obj){ //obj是一个全局变量,实例一次Account创建一个obj对象,是可以被共享的 /*Object obj1=new Object(); synchronized (obj1){*/ //obj1是一个局部变量,每调用一次run方法则会创建一个obj1对象,所以obj1不是共享对象 //synchronized (null){ //报错:空指针 //synchronized ("abc"){ //"abc"在字符串常量池当中,会让所有的线程都同步 synchronized (this){ double before = this.getRemain(); //取款之前的余额 double after = before - money; //取款之后的余额 try{ Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } this.setRemain(after); //更新余额 } } }
AccountThread类
package ATM; public class AccountThread extends Thread { //两个线程必须共享同一个账户对象 private Account act; private double money; //取款金额 //通过构造方法传递过来构造对象 public AccountThread(Account act,double money) { this.act = act; this.money=money; } @Override public void run() { //run方法执行表示取款操作 act.withdraw(money); System.out.println(Thread.currentThread().getName()+"在账户"+ act.getAccountName()+"取款"+money+"之后余额为:"+act.getRemain()); } }
package ATM; public class Test { public static void main(String[] args) { Account act=new Account("act001",10000); //创建账户对象 //创建两个线程,对同一账户取款 Thread threadA=new AccountThread(act,5000); Thread threadB=new AccountThread(act,3000); threadA.setName("小明"); threadB.setName("小华"); threadA.start(); threadB.start(); } }
//synchronized可以用在实例方法上,此时锁是this public synchronized void withdraw(double money) { double before = this.getRemain(); //取款之前的余额 double after = before - money; //取款之后的余额 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } this.setRemain(after); //更新余额 } }
4.5.2、java中的线程安全性
4.5.3、synchronized总结
package Synchronized; //Q:doOther方法执行的时候需要等待doSome方法的结束吗? //A:需要,因为静态方法是类锁,不管创建了几个对象,类锁只有1把 public class Exam01 { public static void main(String[] args) throws InterruptedException { MyClass mc1 = new MyClass(); MyClass mc2 = new MyClass(); Thread t1 = new Mythread(mc1); Thread t2 = new Mythread(mc2); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000); t2.start(); } } class Mythread extends Thread { private MyClass mc; public Mythread(MyClass mc) { this.mc = mc; } @Override public void run() { super.run(); if (Thread.currentThread().getName().equals("t1")) { try { mc.doSome(); } catch (InterruptedException e) { e.printStackTrace(); } } if (Thread.currentThread().getName().equals("t2")) { mc.doOther(); } } } class MyClass { //synchronized出现在静态方法上是走 类锁 public synchronized static void doSome() throws InterruptedException { System.out.println("doSome begin"); Thread.sleep(1000 * 5); System.out.println("doSome over"); } public synchronized static void doOther() { System.out.println("doOther begin"); System.out.println("doOther over"); } }
4.5.4、死锁
package Thread; /* 实现一个死锁, t1中obj1锁上后就睡了,t2中obj2锁上后就睡了。 t1想要释放obj1锁,就必须请求到obj2锁 t2想要释放obj2锁,就必须请求到obj1锁 t1与t2互相请求锁,但彼此都无法释放锁,所以形成了死锁 */ public class Dead_lock { public static void main(String[] args) { Object obj1 = new Object(); Object obj2 = new Object(); //t1,t2两个线程共享o1,o2 Thread t1 = new MyThread_1(obj1, obj2); Thread t2 = new MyThread_2(obj1, obj2); t1.start(); t2.start(); } } class MyThread_1 extends Thread { Object obj1 = new Object(); Object obj2 = new Object(); public MyThread_1(Object obj1, Object obj2) { this.obj1 = obj1; this.obj2 = obj2; } @Override public void run() { synchronized (obj1) { try { Thread.sleep(1000 * 3); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj2) { } } } } class MyThread_2 extends Thread { Object obj1 = new Object(); Object obj2 = new Object(); public MyThread_2(Object obj1, Object obj2) { this.obj1 = obj1; this.obj2 = obj2; } @Override public void run() { synchronized (obj2) { try { Thread.sleep(1000 * 3); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj1) { } } } }
4.6、守护线程
4.6.1、守护线程的特点
4.6.2、一个简单的守护线程的例子
package Thread; /** * 用户线程备份数据,守护线程守护。 */ public class GuardThread { public static void main(String[] args) { Thread thread = new BakDataThread(); thread.setName("备份数据的线程"); //启动线程之前,将线程设置为守护线程 thread.setDaemon(true); thread.start(); for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + "--->" + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } class BakDataThread extends Thread { @Override public void run() { int i = 0; //即使是死循环,但由于该线程是守护者。当用户线程结束,守护线程自动终止 while (true) { System.out.println(Thread.currentThread().getName() + "--->" + i++); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
5、定时任务
5.1、实现一个定时器
package Thread; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class TimerTest { public static void main(String[] args) throws ParseException { //创建定时器对象 Timer timer = new Timer(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date firstTime = sdf.parse("2020-07-25 19:10:30"); //指定定时任务 //timer.schedule(定时任务,第一次执行时间时间,间隔多久执行一次) timer.schedule(new LogTimerTask(), firstTime, 1000 * 5); } } //编写一个定时任务 class LogTimerTask extends TimerTask { @Override public void run() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String strTime = sdf.format(new Date()); System.out.println(strTime + ":成功完成了一次数据备份!"); } }
6、通过Callable接口实现一个线程
package Thread; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class ThirdWay { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask futureTask = new FutureTask(new Task()); Thread thread = new Thread(futureTask); thread.start(); Object object = futureTask.get(); //通过get方法可以获取当前线程的返回值 ////主线程中这里的程序必须等待get()方法结束才执行 // get()方法为了拿另一个线程的执行结果需要等待其执行完成,因此要等待较长时间 System.out.print("线程执行结果:"); System.out.println(object); } } class Task implements Callable { @Override public Object call() throws Exception { System.out.println("call method begin"); Thread.sleep(1000 * 10); System.out.println("call method end"); int a = 100; int b = 200; return a + b; } }
FutureTask类相关源码
public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable }
public V get() throws InterruptedException, ExecutionException { int s = state; if (s <= COMPLETING) s = awaitDone(false, 0L); return report(s); }
7、Object类中的wait和notify方法
7.1、wait和notify方法介绍
Object object=new Object(); object.wait();//object.wait()让正在object对象上活动的线程进入等待状态,无限等待,直到被唤醒为止 object.notify();//object.notify()唤醒正在object对象上等待的线程 object.notifyAll();//object.notifyAll唤醒正在object对象上等待的所有线程
7.2、生产者和消费者模式
package Thread; import java.awt.*; import java.util.*; import java.util.List; public class Producer_Consumer { public static void main(String[] args) { List<String> list = new ArrayList<String>(); Thread thread1 = new Thread(new Consumer(list), "消费者线程"); Thread thread2 = new Thread(new Producer(list), "生产者线程"); thread1.start(); thread2.start(); } } //消费者线程 class Consumer implements Runnable { //仓库 private List<String> list; public Consumer(List<String> list) { this.list = list; } @Override public void run() { //消费 while (true) { synchronized (list) { //如果仓库已经空了,消费者线程等待并释放list集合的锁 if (list.size() == 0) { try { list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //仓库中有商品,消费者进行消费 String str = list.remove(0); System.out.println(Thread.currentThread().getName() + " 消费 " + str); list.notify(); //唤醒生产者 } } } } //生产者线程 class Producer implements Runnable { //仓库 private List<String> list; public Producer(List<String> list) { this.list = list; } @Override public void run() { //生产 while (true) { synchronized (list) { //如果仓库里有东西,则停止生产。生产者线程等待并释放list集合的锁 if (list.size() > 0) { try { list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } list.add("商品"); System.out.println(Thread.currentThread().getName() + " 生产 " + list.get(0)); list.notify(); //唤醒消费者 } } } }
7.3、实现奇偶数的交替输出
package Thread; /** * 使用生产者和消费者模式实现两个线程交替输出:一个线程负责输出奇数,另一个线程负责输出偶数 */ public class Number { public static void main(String[] args) throws InterruptedException { Num num = new Num(0); Thread thread1 = new Thread(new Odd(num), "Odd"); Thread thread2 = new Thread(new Event(num), "Event"); thread1.start(); thread2.start(); } } class Odd implements Runnable { Num num; public Odd(Num num) { this.num = num; } @Override public void run() { while (true) { synchronized (num) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (num.getI() % 2 == 0) { try { num.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "--->" + num.printNum()); num.notifyAll(); } } } } class Event implements Runnable { Num num; public Event(Num num) { this.num = num; } @Override public void run() { while (true) { synchronized (num) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (num.getI() % 2 != 0) { try { num.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "--->" + num.printNum()); num.notifyAll(); } } } } class Num { private int i = 0; public Num(int i) { this.i = i; } public int getI() { return i; } public void setI(int i) { this.i = i; } int printNum() { return i++; } }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算