多线程基础(一)
来源:互联网 发布:怎么开淘宝店铺 编辑:程序博客网 时间:2024/06/11 18:23
一. 线程与进程
1.进程:是一个正在执行中的程序。 每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者控制单元。
线程:就是一个进程中的一个独立执行的控制单元。
线程控制着进程的执行,一个进程至少有一个线程。
2. 线程的几种状态:
1)创建
new Thread() 以及子类对象
2)运行
3)冻结 sleep wait 没有执行资格
4)消亡 stop()
5)阻塞状态:具备运行资格,但是没有执行权
3. 线程的标识:(详细使用见例2)
1)setName GetName
2)Thread.CurrentThread 静态对象,获取当前线程对象
getName():获取线程名称
二. thread类用于描述线程,有两种方法
1.方法一:继承
步骤:
(1)定义类继承Thread类
(2)重写run方法
目的:将自定义的代码存储在run方法中,让线程运行
(3)在主函数中new一个对象,创建线程
(4)thread.start() 启动并执行线程
结果:.
运行结果每次都不同,原因是每个线程都在抢夺CPU的使用权,
在同一时刻,只能有一个程序运行
原因分析:
1.为什么要覆盖run方法
Thread用于描述线程,该类定义了一个功能用于存储线程要运行的代码,
该存储功能就是run方法。也就是Thread类中的run方法用于存储线程要运行的代码
2.为什么不使用d.run()方法?
d.run() 仅仅是对象调用方法,而线程创建了并没有运行。
//有两个进程在同时执行,一个是主函数的进程Hello World,另外一个是demo run进程
例一
class Demo extends Thread{ public void run(){ for(int x=0;x<80;x++) System.out.println("demo run--->"+x); } } public class ThreadDemo { public static void main(String[] args) { // TODO Auto-generated method stub Demo d=new Demo();//创建好一个线程 d.start(); for(int x=0;x<60;x++){ System.out.println("Hello World--->"+x); } } }
例2 设置线程名称
class Test extends Thread{ private String name; Test(String name){ //this.name=name; super(name); } public void run(){ for(int i=0;i<60;i++) System.out.println(this.getName()+" test run--->"+i); } } public class testRun { public static void main(String[] args) { // TODO Auto-generated method stub Test t1=new Test("one--"); Test t2=new Test("two++"); t1.start(); t2.start(); for(int x=0;x<60;x++){ System.out.println(Thread.currentThread().getName()+" main--->"+x); } } }
2.方法二:实现runnable接口
步骤:
1.定义一个类实现runnable接口
2.复写run方法
将线程运行代码存放在该方法中
3.创建类对象
3.创建多个线程
4.线程调用类对象,即将类对象作为参数传递
原因:自定义的run方法所属对象为runable接口的子类对象,
所以要让线程去指定对象的run方法。必须明确run所属对象
5.线程调用start开启线程
对比:
方法一和方法二的区别:
(1) java只支持单继承,一个Ticket继承Thread后,不能继承其他类
实现多个接口,实现方式避免了单继承的局限性,在定义线程时,建议使用接口。
(2) 继承Thread:线程代码存放在Thread的run方法中
实现runnable:线程代码存放在runnable的run方法中
三. 线程同步
同步有两种方式:同步代码块和同步函数。
同步的前提条件:
(1)有两个或者两个以上的线程
(2)必须多个线程使用同一个锁
好处:解决多线程的安全问题
弊端:多个线程都需要判断锁,消耗资源
如何找问题:
(1)明确那些代码是多线程运行代码
(2)明确共享数据
(3)明确多线程运行代码中哪些语句是操作共享数据的
1. 同步代码块中的synchronized的参数必须为一个对象
这时,直接实例化object类
售票的同步代码块:
class Ticket implements Runnable{ private int tick=100; Object obj=new Object(); public void run(){ while(true){ synchronized (obj) { if(tick>0){ try { //不能抛出异常,原因是:run方法复写了父类的run方法, //父类没有设置抛出,因而不能抛出异常,只能处理异常 Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" sale:"+tick--); } } } }}
售票的同步函数(一)
class Ticket implements Runnable{ private int tick=100; Object obj=new Object(); public void run(){ while(true){ this.show(); } } public synchronized void show(){ if(tick>0){ try { //不能抛出异常,原因是:run方法复写了父类的run方法, //父类没有设置抛出,因而不能抛出异常,只能处理异常 Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" sale:"+tick--); } }}
售票的同步函数(二)——静态修饰符
class Ticket implements Runnable{ private static int tick=100; Object obj=new Object(); public void run(){ while(true){ this.show(); } } public static synchronized void show(ticket.class){ if(tick>0){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" sale:"+tick--); } }}
四. 实例:1,2,3,4个窗口卖出100张票
采用方法一:
class Ticket extends Thread{ private String name; Ticket(String name){ super(name); } private static int tick=100; public void run(){ while(true){ if(tick>0){ System.out.println(Thread.currentThread().getName()+" sale:"+tick--); } } } } public class SellTicket { public static void main(String[] args) { // TODO Auto-generated method stub Ticket t1=new Ticket("t1--"); Ticket t2=new Ticket("t2--"); Ticket t3=new Ticket("t3--"); Ticket t4=new Ticket("t4--"); t1.start(); t2.start(); t3.start(); t4.start(); } }
采用方法二:
synchronized用于同步代码块
原因:没有synchronized时发现打印除-1,0等错票,即多线程的运行出现了安全问题
问题产生原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,
另一个线程参与进来执行,导致共享数据的错误
class Ticket implements Runnable{ private int tick=100; Object obj=new Object(); public void run(){ while(true){ synchronized (obj) { if(tick>0){ //不能抛出异常,原因是:run方法复写了父类的run方法,父类没有设置抛出,因而不能抛出异常,只能处理异常 try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" sale:"+tick--); } } } } } public class SellTicket { 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(); } } ```
五. 单例模式与同步块
1.单例模式有两种:饿汉式和懒汉式
饿汉式单例模式代码
class Single{ private static final Single a=new Single(); private Single(); public static Single getInstance(){ return a; } }
懒汉式单例模式代码
class Single{ private static Single a=null; private Single(){} public static Single getInstance(){ if(a==null) { synchronized(Single.class){ if(a==null) a=new Single(); } } return a; }}
2.
(1)饿汉式与懒汉式区别
饿汉式用于延迟加载
(2)饿汉式的单例模式带来的问题
带来安全问题,可能由于多个线程实例化多个对象
(3)怎样解决安全问题:
同步
有两种方式:同步代码块和同步函数
(4)同步带来的问题
需要判断是否已经实例化对象,效率低下
(5)如何解决这个问题
使用同步代码块进行双重判断
六. 死锁
产生死锁的代码块
class Te implements Runnable{ private boolean flag; Te(boolean flag){ this.flag=flag; } public void run(){ if(flag){ synchronized(MyLock.looka ) { System.out.println("if looka"); synchronized(MyLock.lookb ){ System.out.println("if lookb"); } } } else{ synchronized(MyLock.lookb){ System.out.println("else lookb"); synchronized(MyLock.looka){ System.out.println("else looka"); } } } } }class MyLock{ static Object looka=new Object(); static Object lookb=new Object();}public class DeadLockTest { public static void main(String[] args) { Thread t1=new Thread(new Te(true)); Thread t2=new Thread(new Te(false)); t1.start(); t2.start(); }}
- linux多线程基础(一)
- 多线程基础一
- 一、多线程基础
- java多线程基础一
- 多线程基础(一)
- java多线程基础一
- 多线程(一)多线程基础、多线程状态
- 多线程编程(一)多线程基础
- java多线程(一)多线程基础
- iOS 多线程(一)多线程基础
- 多线程编程 基础篇 (一)
- JAVA多线程基础(一)
- java多线程基础篇一
- java多线程基础(一)
- JAVA多线程基础(一)
- 多线程编程 基础篇 (一)
- 【多线程编程】基础篇一
- 多线程基础篇(一)
- 性能测试学习方式
- Fragment切换再现覆盖卡顿
- 【LeetCode】Max Consecutive Ones 解题报告
- 用一条语句判断一个整数是不是2的整数次方
- CCF201312--模拟练习试题参考答案(Java)
- 多线程基础(一)
- ubuntu 安装nsf(Network File System)与配置服务
- 微信小程序 仿美团分类菜单 swiper分类菜单
- jdk源码阅读二:LinkedList
- 自己搭建ngrok服务器实现树莓派内网穿透
- copyWithin的call调用实例——关于this
- 复式记账:借贷记账法
- 开发一个 app 有多难?
- ffmpeg官网例子