Java学习笔记之——多线程(一)
2015-08-29 17:47
471 查看
Java学习笔记之
多线程(一)——线程的创建
线程的概念:线程是程序中一个单一的顺序控制流程,是进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
线程在控制着进程的执行,一个进程中至少有一个线程,一个线程必须有一个父进程。
为了正确有效地使用线程,必须理解线程的各个方面并了解Java 实时系统。必须知道如何提供线程体、线程的生命周期、实时系统如 何调度线程、线程组、什么是幽灵线程(Demo nThread)。
Java VM启动时会有一个进程java.exe,该进程中至少有一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称之为主线程。
JVM启动不止一个线程,还有负责垃圾回收机制的线程。
守护线程
守护线程是特殊的线程,一般用于在后台为其他线程提供服务.
Java中,isDaemon():判断一个线程是否为守护线程.
Java中,setDaemon():设置一个线程为守护线程.
幽灵线程
任何一个Java线程都能成为幽灵线程。它是作为运行于同一个进程内的对象和线程的服务提供者。例如,HotJava浏览器有一个称为" 后台图片阅读器"的幽灵线程,它为需要图片的对象和线程从文件系统或网络读入图片。 幽灵线程是应用中典型的独立线程。它为同一应用中的其他对象和线程提供服务。幽灵线程的run()方法一般都是无限循环,等待服务请求。
创建新执行线程有两种方法:
方法一:继承
步骤:
1.定义类继承Thread
2.复写Thread类中的run方法(Thread中的run方法用于存储线程要执行的代码。复写的目的:将自定义的代码存储于run方法,让线程运行)
3.调用线程的strat方法,该方法用于启动线程,调用run方法
....
每次运行结果不尽相同,因为多个线程都获取cpu的执行权,cup执行到谁,谁运行。某一时刻,只能一个程序运行(多核除外)。cpu在做着快速切换,已达到同时运行的效果。多线程的随机性,互相抢夺cpu的执行权。
start和run的区别:
如果不调用start方法,而直接调用run方法(如下),则程序会顺序先执行完Demo类中的输出,在执行主函数中的输出,此时已经不是多线程。因为创建的线程没有启动。
线程的状态:
获取线程对象和名称:
static Thread currentThread():获取当前线程。
线程都有自己默认的名称。 Thread-编号,该编号从0开始。
getName():获取线程名称。
自定义线程名称:setName()或者Thread类提供的传递线程名称的构造函数Thread(String name)
方法二:实现Runnable接口
步骤:
1.定义类实现Runnable接口
2.覆盖Runnable接口中的run方法
3.通过Thread类建立线程对象
aad4
4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
如下是一个多窗口售票程序:
实现方式和继承方式的区别:
实现方式避免了单继承的局限性。如:student类继承了person类,这时如果student类需要实现多线程,则无法再继承Thread类。
在定义线程时,建议使用实现方式。
存放代码位置不一样:
继承Thread:线程代码存放在Thread子类run方法中
实现Runnable:线程代码存放在接口的子类run中
多线程的安全问题:
如果在上述代码中,执行if(tick>0)时,线程被挂起,转而执行其他线程,这时就可能出现错误。
稍微改动一下代码,利用Thread中的sleep()函数让线程执行到if语句时停一会:
打印出了0,-1,-2等错票,多线程运行出现安全问题。
原因: 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来,导致共享数据错误。
一般情况下,在程序测试阶段,很难发现这类安全错误。
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。
Java关于多线程安全问题解决方式:同步代码块
synchronized(对象)
{
需要被同步的代码
}
对象如同锁,持有锁的线程可以在同步中执行,没有持有锁的线程即使获取cpu执行权也进不去,必须要设置锁。
同步的前提:
1.必须要有两个或两个以上的线程。
2.必须是多个线程使用同一个锁
必须保证同步中只有一个线程在运行
好处:解决了多线程的安全问题
弊端:多个线程需要判断锁,较为消耗资源
上述程序代码改动如下:
多线程(一)——线程的创建
线程的概念:线程是程序中一个单一的顺序控制流程,是进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
线程在控制着进程的执行,一个进程中至少有一个线程,一个线程必须有一个父进程。
为了正确有效地使用线程,必须理解线程的各个方面并了解Java 实时系统。必须知道如何提供线程体、线程的生命周期、实时系统如 何调度线程、线程组、什么是幽灵线程(Demo nThread)。
Java VM启动时会有一个进程java.exe,该进程中至少有一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称之为主线程。
JVM启动不止一个线程,还有负责垃圾回收机制的线程。
守护线程
守护线程是特殊的线程,一般用于在后台为其他线程提供服务.
Java中,isDaemon():判断一个线程是否为守护线程.
Java中,setDaemon():设置一个线程为守护线程.
幽灵线程
任何一个Java线程都能成为幽灵线程。它是作为运行于同一个进程内的对象和线程的服务提供者。例如,HotJava浏览器有一个称为" 后台图片阅读器"的幽灵线程,它为需要图片的对象和线程从文件系统或网络读入图片。 幽灵线程是应用中典型的独立线程。它为同一应用中的其他对象和线程提供服务。幽灵线程的run()方法一般都是无限循环,等待服务请求。
创建新执行线程有两种方法:
方法一:继承
Thread类。该子类应重写
Thread类的
run方法
步骤:
1.定义类继承Thread
2.复写Thread类中的run方法(Thread中的run方法用于存储线程要执行的代码。复写的目的:将自定义的代码存储于run方法,让线程运行)
3.调用线程的strat方法,该方法用于启动线程,调用run方法
<span style="font-size:18px;">import java.lang.Thread; class Demo extends Thread{ public void run() { for(int x=0; x<40; x++) System.out.println("demo run--"+x); } } class TreadDemo{ public static void main(String[] args) { Demo d = new Demo();//创建一个线程 d.start(); for(int x=0; x<40; x++) System.out.println("Hello World!--"+x); } }</span>运行结果:
....
每次运行结果不尽相同,因为多个线程都获取cpu的执行权,cup执行到谁,谁运行。某一时刻,只能一个程序运行(多核除外)。cpu在做着快速切换,已达到同时运行的效果。多线程的随机性,互相抢夺cpu的执行权。
start和run的区别:
如果不调用start方法,而直接调用run方法(如下),则程序会顺序先执行完Demo类中的输出,在执行主函数中的输出,此时已经不是多线程。因为创建的线程没有启动。
Demo d = new Demo();//创建一个线程 //d.start(); d.run();
线程的状态:
获取线程对象和名称:
static Thread currentThread():获取当前线程。
线程都有自己默认的名称。 Thread-编号,该编号从0开始。
getName():获取线程名称。
自定义线程名称:setName()或者Thread类提供的传递线程名称的构造函数Thread(String name)
<span style="font-size:18px;">import java.lang.Thread; class Demo extends Thread{ Demo(String name) { super(name);//调用父类 } public void run() { for(int x=0; x<40; x++) System.out.println(this.getName()+" run--"+x);//或者Thread.currentThread().getName() } } class TreadDemo{ public static void main(String[] args) { Demo d1 = new Demo("one");//创建一个线程 Demo d2 = new Demo("two"); d1.start(); d2.start(); for(int x=0; x<40; x++) System.out.println("Hello World!--"+x); } }</span>
方法二:实现Runnable接口
步骤:
1.定义类实现Runnable接口
2.覆盖Runnable接口中的run方法
3.通过Thread类建立线程对象
aad4
4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
如下是一个多窗口售票程序:
<span style="font-size:18px;">import java.lang.Thread; 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(); } }</span>打印结果:
实现方式和继承方式的区别:
实现方式避免了单继承的局限性。如:student类继承了person类,这时如果student类需要实现多线程,则无法再继承Thread类。
在定义线程时,建议使用实现方式。
存放代码位置不一样:
继承Thread:线程代码存放在Thread子类run方法中
实现Runnable:线程代码存放在接口的子类run中
多线程的安全问题:
如果在上述代码中,执行if(tick>0)时,线程被挂起,转而执行其他线程,这时就可能出现错误。
稍微改动一下代码,利用Thread中的sleep()函数让线程执行到if语句时停一会:
<span style="font-size:18px;">if(tick>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+" sale:"+tick--); }</span>执行结果:
打印出了0,-1,-2等错票,多线程运行出现安全问题。
原因: 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来,导致共享数据错误。
一般情况下,在程序测试阶段,很难发现这类安全错误。
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。
Java关于多线程安全问题解决方式:同步代码块
synchronized(对象)
{
需要被同步的代码
}
对象如同锁,持有锁的线程可以在同步中执行,没有持有锁的线程即使获取cpu执行权也进不去,必须要设置锁。
同步的前提:
1.必须要有两个或两个以上的线程。
2.必须是多个线程使用同一个锁
必须保证同步中只有一个线程在运行
好处:解决了多线程的安全问题
弊端:多个线程需要判断锁,较为消耗资源
上述程序代码改动如下:
<span style="font-size:18px;">class Ticket implements Runnable { private int tick = 100;//总票数 Object obj = new Object(); public void run() { while(true) { synchronized(obj)//取值为0或1,表示开关 { if(tick>0) { try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+" sale:"+tick--); } } } } }</span>问题解决!!
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Python3写爬虫(四)多线程实现数据爬取
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树