java学习之多线程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
线程(Lightweight
Process,LWP)是程序中一个单一的顺序控制流程,有时被称为轻量级进程,是程序执行流的最小单元。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
每一个单进程==多个线程的组合
javav中线程实现的两种方式:
1.继承Thread类
首先覆盖Thread中的run方法
public class MyThread extends Thread { private String name; // 定义name属性 public MyThread(String name) { this.name = name; } public void run() {// 覆写run()方法 for (int i = 0; i < 50; i++) {// 表示循环10次 System.out.println("Thread运行:" + name + ",i = " + i); } } }
因为线程的启动需要借助底层函数,因此无法通过实例化MyThread后调用run方法直接完成,而必须通过可以启动底层函数的start()方法来启动线程。
public class ThreadDemo02 { public static void main(String[] args) { MyThread mt1 = new MyThread("线程A"); MyThread mt2 = new MyThread("线程B"); mt1.start(); // 调用线程体 mt2.start(); // 调用线程体 } }
start()方法在jdk1.5中的源码
2.实现Runnable接口
public class MyThread implements Runnable { // 实现Runnable接口 private String name; // 定义name属性 public MyThread(String name) { this.name = name; } public void run() {// 覆写run()方法 for (int i = 0; i < 50; i++) {// 表示循环10次 System.out.println("Thread运行:" + name + ",i = " + i); } } }
public class RunnableDemo01 { public static void main(String[] args) { MyThread mt1 = new MyThread("线程A"); MyThread mt2 = new MyThread("线程B"); new Thread(mt1).start(); // 调用线程体 new Thread(mt2).start(); // 调用线程体 } }通常开发中多用到第二种方法,因为相比于法一,既可以避免单继承局限,又可以实现现资源共享。
法一实现代码:
public class MyThread extends Thread {// 继承Thread类 private int ticket = 5; // 一共才5张票 public void run() {// 覆写run()方法 for (int i = 0; i < 50; i++) {// 表示循环10次 if (this.ticket > 0) { System.out.println("卖票:ticket = " + this.ticket--); } } } }
public class ThreadTicket { public static void main(String[] args) { MyThread mt1 = new MyThread(); // 一个线程 MyThread mt2 = new MyThread(); // 一个线程 MyThread mt3 = new MyThread(); // 一个线程 mt1.start() ; // 开始卖票 mt2.start() ; // 开始卖票 mt3.start() ; // 开始卖票 } }
法二实现代码
public class MyThread implements Runnable {// 实现Runnable接口 private int ticket = 5; // 一共才5张票 public void run() {// 覆写run()方法 for (int i = 0; i < 50; i++) {// 表示循环10次 if (this.ticket > 0) { System.out.println("卖票:ticket = " + this.ticket--); } } } }
public class RunnableTicket { public static void main(String[] args) { MyThread mt = new MyThread(); // 一个线程 new Thread(mt).start() ; // 开始卖票 new Thread(mt).start() ; // 开始卖票 new Thread(mt).start() ; // 开始卖票 } }
很明显法二只有一个线程,共同售卖5张票而法一三个独立的线程各卖出了5张票。
线程的操作:
设置和取得名字
public class MyThread implements Runnable { public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "线程正在运行。"); } } }设置线程名字分别为A、B、C
public class ThreadNameDemo01 { public static void main(String[] args) { MyThread mt = new MyThread(); // Runnable子类实例 Thread thread1 = new Thread(mt, "线程A"); Thread thread2 = new Thread(mt, "线程B"); Thread thread3 = new Thread(mt, "线程C"); thread1.start() ; thread2.start() ; thread3.start() ; } }
在java中,至少会同时执行两个进程,分别为Main线程和GC(java垃圾回收)
public class ThreadNameDemo02 { public static void main(String[] args) { MyThread mt = new MyThread(); // Runnable子类实例 new Thread(mt, "自定义线程").start(); mt.run() ; // 直接通过对象调用 } }
线程的休眠
public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(500); // 每个休眠500毫秒 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "线程正在运行。"); } } }
public class ThreadSleepDemo { public static void main(String args[]){ MyThread mt = new MyThread() ; new Thread(mt,"线程A").start() ; new Thread(mt,"线程B").start() ; } }
线程的中断
class MyThread implements Runnable { public void run() { System.out.println("1、进入run()方法体"); try { System.out.println("2、线程休眠20秒钟"); Thread.sleep(20000); // 每个休眠20秒 System.out.println("3、线程正常休眠20秒钟"); } catch (InterruptedException e) { System.out.println("4、线程休眠被中断"); return;// 返回方法调用处 } System.out.println("5、正常结束run()方法体"); } } public class InterruptDemo { public static void main(String[] args) { MyThread mt = new MyThread(); Thread thread = new Thread(mt, "线程A"); thread.start();// 启动线程 try { Thread.sleep(2000); // 保证程序至少执行2秒 } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); // 中断 } }
设置线程优先级
class MyThread implements Runnable { public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(600) ; // 延迟操作 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "线程正在运行。"); } } } public class PriorityDemo01 { public static void main(String[] args) { MyThread mt = new MyThread(); Thread t1 = new Thread(mt, "线程A"); Thread t2 = new Thread(mt, "线程B"); Thread t3 = new Thread(mt, "线程C"); t1.setPriority(Thread.NORM_PRIORITY); // 将第一个线程设置为中等优先级 t3.setPriority(Thread.MAX_PRIORITY); // 将第三个线程设置为最高优先级 t2.setPriority(Thread.MIN_PRIORITY); // 将第二个线程设置为最低优先级 t1.start(); t2.start(); t3.start(); } }
主方法优先级属于普通优先级。
线程的同步
首先看一个异常售票实例
class MyTicketThread implements Runnable {// 实现Runnable接口 private int ticket = 5; // 一共才5张票 public void run() {// 覆写run()方法 for (int i = 0; i < 50; i++) {// 表示循环10次 if (this.ticket > 0) { try { Thread.sleep(300);// 延迟 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("卖票:ticket = " + this.ticket--); } } } } public class SynDemo01 { public static void main(String[] args) { MyTicketThread mt = new MyTicketThread(); // 一个线程 new Thread(mt, "票贩子-A ").start(); // 开始卖票 new Thread(mt, "票贩子-B ").start(); // 开始卖票 new Thread(mt, "票贩子-C ").start(); // 开始卖票 } }
因为延迟,可能导致售票发生数值异常。
解决办法一:利用synchronized方法设置同步代码使售票程序同步起来,同一时间段只允许一个线程访问、
class MyTicketThread implements Runnable {// 实现Runnable接口 private int ticket = 5; // 一共才5张票 public void run() {// 覆写run()方法 for (int i = 0; i < 50; i++) {// 表示循环10次 synchronized (this) {// 形成同步代码块 if (this.ticket > 0) { try { Thread.sleep(300);// 延迟 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("卖票:ticket = " + this.ticket--); } } } } } public class SynDemo02 { public static void main(String[] args) { MyTicketThread mt = new MyTicketThread(); // 一个线程 new Thread(mt, "票贩子-A ").start(); // 开始卖票 new Thread(mt, "票贩子-B ").start(); // 开始卖票 new Thread(mt, "票贩子-C ").start(); // 开始卖票 } }
解决方法二:设定同步方法
class MyTicketThread implements Runnable {// 实现Runnable接口 private int ticket = 5; // 一共才5张票 public void run() {// 覆写run()方法 for (int i = 0; i < 50; i++) {// 表示循环10次 this.sale(); // 调用同步方法 } } public synchronized void sale() {// 增加同步方法 if (this.ticket > 0) { try { Thread.sleep(300);// 延迟 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("卖票:ticket = " + this.ticket--); } } } public class SynDemo03 { public static void main(String[] args) { MyTicketThread mt = new MyTicketThread(); // 一个线程 new Thread(mt, "票贩子-A ").start(); // 开始卖票 new Thread(mt, "票贩子-B ").start(); // 开始卖票 new Thread(mt, "票贩子-C ").start(); // 开始卖票 } }
线程的死锁
所谓死锁: 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
class FanBo { public synchronized void say(ZhangYang zy) { System.out.println("把钱给我,放了你弟弟。"); zy.give(); } public synchronized void give() { System.out.println("得到了钱,同时被警察抓了。"); } } class ZhangYang { public synchronized void say(FanBo fb) { System.out.println("把弟弟放了,我给你钱。"); fb.give(); } public synchronized void give() { System.out.println("弟弟救回来,同时报案了。"); } } public class DeadLockDemo implements Runnable { private FanBo fb = new FanBo(); private ZhangYang zy = new ZhangYang(); public DeadLockDemo() { new Thread(this).start() ; zy.say(fb); } public void run() { fb.say(zy); } public static void main(String[] args) { new DeadLockDemo(); } }
多个进程共享统一资源的时候需要同步,而过多的同步又会产生死锁。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。