多线程:
程序运行时:启动了两个线程:
Main线程:调用main方法,执行main方法。
GC线程:在main线程运行时运行,回收程序运行之中的垃圾。
线程:一条执行路径。多线程完成多个功能并发并发执行的效果。
多线程之间乱系执行、同一线程内部顺序执行的。
写多线程:
1. 继承自Thread类,重写run方法。然后用Thread的start方法启动线程。
2. 实现Runnable接口,实现run方法。然后用Thread的start方法启动线程。
两种方式的区别:
1. 第一种使用简单。
2. 第二种不受java单继承的限制。一般来说,都是用第二种。
线程中常用的方法:线程中的已过时方法禁止使用。其他类中的过时方法不建议使用。
1. start:启动一个新线程。启动之后jvm会自动执行run方法。
2. run:线程启动之后执行的方法。
3. setName、getName:自动命名,Thread-0,1…
4. currentThread:得到当前运行的线程。
5. getPriority()、setPriority 得到和设置当前线程的优先级。优先级1-10,如果不指定默认是5. 理论上,谁优先级高,谁被cpu调度的可能性就大。但是优先级低的并不是不执行。资源不足的时候才有效果。
6. setDaemon:将线程置为守护线程。只能在线程start之前调用。一般用于为其他线程提供服务,比如GC。守护线程会随着其他非守护线程的结束而结束。isDaemon可以用于判断某个线程是否是守护线程。
7. sleep:让当前线程停止执行(休眠)一段时间。
8. join:如果在A线程中B线程join进来,则现在执行B的内容,直到B执行完毕才继续执行A。比如A是显示数据 B是收集收据。
9. yield:让位:让出执行权,和其他线程争夺资源,谁拿到cpu时间片谁执行。
线程的状态图:说明 run方法结束,新线程结束。
package day16; import java.util.ArrayList; import java.util.Vector; public class Bank { public static void main(String[] args) { // 创建一个账户 Account account = new Account(); // 你和女朋友操作同一个账户 Person1 you1 = new Person1(account); Person1 yourGF1 = new Person1(account); Thread thYou1 = new Thread(you1); Thread thYourGF1 = new Thread(yourGF1); // 你和女朋友同时去取钱。 thYou1.start(); thYourGF1.start(); // 存钱线程 Person2 you2 = new Person2(account); Person2 yourGF2 = new Person2(account); Thread thYou2 = new Thread(you2); Thread thYourGF2 = new Thread(yourGF2); thYou2.start(); thYourGF2.start(); try { Thread.sleep(5000);// 确保账户操作完毕 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("最终账户余额:"+account.balance); } } class Account{ private ArrayList list; private Vector v ; public int balance = 2000; private Object obj1 = new Object(); // private Object obj2 = new Object(); // 取款 public /*synchronized*/ void withdraw(){// 同一时间只能有一个线程访问。 synchronized (obj1) { int temp = balance; temp = temp - 800; try { Thread.sleep(1000);// 模拟网络延迟。 } catch (InterruptedException e) { e.printStackTrace(); } balance = temp; System.out.println(Thread.currentThread().getName()+"取款"); // while(true){} } } // 存款 public /*synchronized*/ void deposit(){// 同一时间只能有一个线程访问。 synchronized (obj1) { int temp = balance; temp = temp + 800; try { Thread.sleep(1000);// 模拟网络延迟。 } catch (InterruptedException e) { e.printStackTrace(); } balance = temp; System.out.println(Thread.currentThread().getName()+"存款"); } } } class Person1 implements Runnable{ // 人要自己的账户。 private Account account ; public Person1(Account account){ this.account = account; } @Override public void run() { account.withdraw(); } } class Person2 implements Runnable{ // 人要自己的账户。 private Account account ; public Person2(Account account){ this.account = account; } @Override public void run() { account.deposit(); } }
线程相关的常用类:
1. Timer:定时器、调度器、计时器。
2. TimerTask:定时任务。
线程间的同步:本质:把异步转化为同步,把并行转为串行。
方式:
1. 同步语句块:synchronized(obj){}
2. 同步方法:在方法前加synchronized修饰符,拿到的仍然是本类对象的锁。
难点:不容易测出来。
对象锁:每个对象都有一把锁。同步锁、互斥锁
package day16; import java.awt.BorderLayout; import java.util.Timer; import java.util.TimerTask; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import com.sun.awt.AWTUtilities; public class Logo extends JFrame{ /** logo下标 **/ private int niIndex = 1; /** 显示图片内容的标签 **/ private JLabel lbShow; /** 计时器 **/ private Timer timer; public Logo(){ JPanel pnBasic = new JPanel(); pnBasic.setLayout(new BorderLayout()); lbShow = new JLabel(); pnBasic.add(lbShow,BorderLayout.CENTER); lbShow.setIcon(new ImageIcon("fff/role1/1.png")); setContentPane(pnBasic); setTitle("欢迎界面"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(200,200,410,320); // 透明 setUndecorated(true); AWTUtilities.setWindowOpaque(this, false); setVisible(true); // 定义定时器 timer = new Timer(); // 1.重复执行的任务 2.延迟多长时间执行 3.执行频率 timer.schedule(new LogoMonitor(),1000,500); } private class LogoMonitor extends TimerTask{ @Override public void run() { if(niIndex<7){ niIndex++; lbShow.setIcon(new ImageIcon("fff/role1/"+niIndex+".png")); }else{ timer.cancel(); dispose(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("进入主界面"); } } } public static void main(String[] args) { new Logo(); } }