java基础之多线程技术
来源:互联网 发布:网络诈骗手段方式 编辑:程序博客网 时间:2024/06/14 16:12
1.线程的概述:
进程:正在进行中的程序(直译)。
线程:就是进程中一个负责程序执行的控制单元(执行路径),
一个进程中可以多执行路径,称之为多线程。
一个进程中至少要有一个线程。
开启多个线程是为了同时运行多部分代码。
每一个线程都有自己运行的内容。这个内容可以称为线程要执行的任务。
多线程好处:解决了多部分同时运行的问题。
多线程的弊端:线程太多回到效率的降低。
其实应用程序的执行都是cpu在做着快速的切换完成的,这个切换是随机的。
JVM启动时就启动了多个线程,至少有两个线程可以分析的出来。
1,执行main函数的线程,该线程的任务代码都定义在main函数中。
2,负责垃圾回收的线程。
2.创建线程的方式
- 创建线程方式一:继承Thread类。
- 创建线程方式二:实现Runnable接口
继承Thread类
步骤:
1,定义一个类继承Thread类。
2,覆盖Thread类中的run方法。
3,直接创建Thread的子类对象创建线程。
4,调用start方法开启线程并调用线程的任务run方法执行。
可以通过Thread的getName获取线程的名称Thread-编号(从0开始)
主线程的名字就是main。
继承Thread类来创建一个线程public class Demo11 { public static void main(String[] args) { Thread1 t= new Thread1(); //t.run();//仅仅是调用了重写的run方法 t.start();//开启线程并执行该线程的run方法。 for (int i = 0; i < 60; i++) { System.out.println("main -- " + i); } }}class Thread1 extends Thread { public void run() { for (int i = 0; i < 60; i++) { System.out.println("Thread1 -- " + i); } }}在控制台可以看到主线程和当前的线程交替输出内容。
我们发现运行结果每一次都不同。
因为多个线程都获取cpu的执行权。cpu执行到谁,谁就运行。
明确一点,在某一个时刻,只能有一个程序在运行。(多核除外)
cpu在做着快速的切换,以达到看上去是同时运行的效果。
我们可以形象把多线程的运行行为在互相抢夺cpu的执行权。
这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长,cpu说的算。
为什么要覆盖run方法呢?
Thread类用于描述线程。
该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。也就是说Thread类中的run方法,用于存储线程要运行的代码。
创建线程的第二种方式:实现Runnable接口。
步骤:
1,定义类实现Runnable接口。
2,覆盖接口中的run方法,将线程的任务代码封装到run方法中。
3,通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。
为什么?因为线程的任务都封装在Runnable接口子类对象的run方法中。
所以要在线程对象创建时就必须明确要运行的任务。
4,调用线程对象的start方法开启线程。
实现Runnable接口的好处:
1,将线程的任务从线程的子类中分离出来,进行了单独的封装。
按照面向对象的思想将任务的封装成对象。
2,避免了java单继承的局限性。
所以,创建线程的第二种方式较为常用。
例如:
public class Demo12 { public static void main(String[] args) { ThreadImpl t = new ThreadImpl(); Thread thread = new Thread(t); thread.start(); }}class ThreadImpl implements Runnable { @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println("Thread--" + i); } } }
3.多线程典型案例之银行存钱
需求:银行有一个金库。有两个储户每次存100,存3次。
目的:该程序是否有安全问题,如果有,如何解决?
如何找问题:
1,明确哪些代码是多线程运行代码。
2,明确共享数据。
3,明确多线程运行代码中哪些语句是操作共享数据的。
class Bank{ private int sum; //Object obj = new Object(); public synchronized void add(int n)//加入同步锁机制 这是一个同步函数 { //synchronized(obj) //{ sum = sum + n; try{Thread.sleep(10);}catch(Exception e){} System.out.println("sum="+sum); //} }}class Cus implements Runnable{ private Bank b = new Bank(); public void run() { for(int x=0; x<3; x++) { b.add(100); } }}class BankDemo{ public static void main(String[] args) { Cus c = new Cus(); Thread t1 = new Thread(c); Thread t2 = new Thread(c); t1.start(); t2.start(); }}
4.多线程典型案例之卖票
下面这个程序会出现多个窗口卖同一张票的事情。还有可能打印出0,-1,-2等错票。
多线程的运行出现了安全问题。
class Ticket implements Runnable{ private int tick = 100; public void run() { while(true) { if(tick>0) { System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--); } } }}class TicketDemo{ public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t);//创建了一个线程; Thread t2 = new Thread(t);//创建了一个线程; Thread t3 = new Thread(t);//创建了一个线程; Thread t4 = new Thread(t);//创建了一个线程; t1.start(); t2.start(); t3.start(); t4.start(); }}
上面问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
Java对于多线程的安全问题提供了专业的解决方式。就是同步代码块。
同步代码块的格式:synchronized(对象){ 需要被同步的代码}
加了同步代码块之后:
class Ticket implements Runnable{ private int tick = 1000; Object obj = new Object(); public void run() { while(true) { synchronized(obj) { if(tick>0) { System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--); } } } }}class TicketDemo2{ public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); Thread t3 = new Thread(t); Thread t4 = new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); }}
对象如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。
例如:火车上的卫生间
同步的前提:
1,必须要有两个或者两个以上的线程。
2,必须是多个线程使用同一个锁。
必须保证同步中只能有一个线程在运行。
多线程同步的好处和弊端
好处:解决了多线程的安全问题。
弊端:多个线程需要判断锁,较为消耗资源。
5.同步代码块和同步函数
同步函数用的是哪一个锁呢?
函数需要被对象调用。那么函数都有一个所属对象引用。就是this。所以同步函数使用的锁是this。
通过该程序进行验证。
使用两个线程来买票。
一个线程在同步代码块中。
一个线程在同步函数中。
都在执行买票动作。
静态的同步方法,使用的锁是该方法所在类的字节码文件对象。 类名.class
class Ticket implements Runnable { private int tick = 100; //Object obj = new Object(); boolean flag = true; public void run() { if(flag) { while(true) { synchronized(this) { //synchronized(Ticket.class) if(tick>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"....code : "+ tick--); } } } } else while(true) show(); } public synchronized void show()//this { if(tick>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--); } }}class ThisLockDemo{ public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try{Thread.sleep(10);}catch(Exception e){} t.flag = false; t2.start(); }}
6.多线程之死锁
死锁产生的原因:同步中嵌套同步。
class Test implements Runnable{ private boolean flag; Test(boolean flag) { this.flag = flag; } public void run() { if(flag) { while(true) { synchronized(MyLock.locka) { System.out.println(Thread.currentThread().getName()+"...if locka "); synchronized(MyLock.lockb) { System.out.println(Thread.currentThread().getName()+"..if lockb"); } } } } else { while(true) { synchronized(MyLock.lockb) { System.out.println(Thread.currentThread().getName()+"..else lockb"); synchronized(MyLock.locka) { System.out.println(Thread.currentThread().getName()+".....else locka"); } } } } }}//定义两个锁对象class MyLock{ static Object locka = new Object(); static Object lockb = new Object();}class DeadLockTest{ public static void main(String[] args) { Thread t1 = new Thread(new Test(true)); Thread t2 = new Thread(new Test(false)); t1.start(); t2.start(); }}
7.线程的四种状态
- java基础之多线程技术
- java基础之多线程
- java基础之多线程
- Java基础之多线程
- java基础之多线程
- java基础之多线程
- Java基础之多线程
- Java基础之多线程
- Java基础之多线程
- JAVA基础之多线程
- Java基础之多线程
- java基础之多线程
- Java基础之多线程
- java基础之多线程
- java基础之多线程
- Java基础之多线程
- Java基础之多线程
- Java基础之多线程
- 安卓开发利用闪光灯实现手电筒功能
- 第3课 02 JS中级课程-event-事件对象和clientX,clientY-2
- 华为——字符串分隔
- 《Hadoop.The.Definitive.Guide.4th.Edition.2015.3》学习笔记
- Java异常Exception
- java基础之多线程技术
- PHP中重载
- 拦截tablayout 点击事件,不触发viewpaper滚动 例如登陆检测等场景
- Spring学习笔记一
- 10014---Java面试题全集(下)
- 第3课 02 JS中级课程-event-事件(跟随鼠标移动的div)
- RouterOS+NTOPNG两件套
- 每个Linux开发者都应该知道的一些知识
- Spring IOC笔记