进程 和 线程
进程是操作系统结构的基础,是一个正在执行的程序,计算机中正在运行的程序实例。
线程是进程中某个单一顺序的控制流,是程序运行的基础执行单位,任何一个程序中至少需要一个主线程。
单线程
优点:程序执行思路步骤清晰,顺序分明。
缺点:一次只能做一个事件,必须做完一件事后才能继续做另一件事。
单线程的优缺点就是多线程的缺优点。
使用线程的好处:
异步处理、简化编程模型、提高CPU使用
Swing是JAVA中图形开发技术
在图形中,按钮等组件如果需要通过单击等动作来触发代码的执行需要使用事件驱动机制。
如果在类的使用过程中需要使用另一个类的实例,同时该类中的代码无法在其他类进行复用,这种场合一般使用内部类或者匿名类来解决,如果该类能够在当前类的内部进行复用则应该写成内部类的形式,反之无法复用的类型则应写成匿名类的形成。
线程的创建
1、继承Thread类
2、实现Runnable接口
无论使用哪种方式都必须要重写run方法,该方法是线程的核心,用来描述线程所要执行的业务逻辑。
方式一:
/**
* 使用继承实现自定义线程
*
* @author Administrator
*
*/
publicclassMyThread1extendsThread{
/**
* 构造方法
* @param name 线程的命名
*/
publicMyThread1(String name){
super(name);
//此时线程处于准备就绪状态
System.out.println(getState());
System.out.println(isAlive());
}
@Override
publicvoid run(){
//此时线程处于运行时的状态
System.out.println(getState());
//判断线程是否处于存活状态,只有当线程在run方法中执行时,isAlive才会返回true,该方法的功能和getState == State.RUNNABLE相同
System.out.println(isAlive());
for(int i =1; i <=10; i++){
System.out.println(getName()+":"+i);
}
}
}
/**
* 使用接口的方式实现线程
* @author Administrator
*
*/
publicclassMyThread2implementsRunnable{
@Override
publicvoid run(){
for(int i =1; i <=10; i++){
//Thread.currentThread()表示获取当前正在运行的线程
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
线程的生命周期
1、准备就绪 new
2、运行时 runnable
3、阻塞等待 wait
4、终止完成 terminated
/**
* 控制时间的线程
* @author Administrator
*
*/
privateclassTimeThreadextendsThread{
publicvoid run(){
// while(true){
// //设置当前系统时间至标签
// lblTime.setText(getTime());
// //每次刷新时间让当前线程等待一秒
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
// while(flag){
// //也可以通过死循环中添加if(flag)的方式来控制
// //设置当前系统时间至标签
// lblTime.setText(getTime());
// //每次刷新时间让当前线程等待一秒
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
while(!isInterrupted()){
lblTime.setText(getTime());
//每次刷新时间让当前线程等待一秒
try{
Thread.sleep(1000);
}catch(InterruptedException e){
// TODO Auto-generated catch block
//e.printStackTrace();
interrupt();
}
}
}
}
线程的方法
getState()获取线程的当前状态
isAlive()判断线程是否处于存活状态,只有当线程在run方法中执行时,isAlive才会返回true
start()启动线程
stop()终止当前线程(过时方法)
suspend()挂起线程
(过时方法)resume()继续挂起的线程
(过时方法)join()等待线程执行完毕,表示将线程加入队列,使得线程按照一定的顺序执行
yield()暂缓线程
sleep()线程等待
wait()线程等待
notify()唤醒线程
线程引起阻塞的方法
suspend、join、yield、sleep、wait
run()方法不需要我们自己调用,当调用start()方法时将自动调用run方法,直到run方法执行完毕或人为停止或挂起
sleep表示让当前线程阻塞若干毫秒,当阻塞时间过后线程将自动回复运行
stop方法允许在任何环境对指定的线程进行关闭操作,stop关闭的线程将释放该线程的对象锁,如果有其他线程对其锁定的对象进行访问,将导致线程的执行顺序出现问题,从而使多条线程的允许结果也同样出错。
一条运行结束后的线程不能再次通过start方法再次开启。
suspend 和resume方法容易引起线程的死锁
多条数据对同一个数据都进行访问,这种访问机制就称为线程的并发访问。
解决线程的并发问题可以通过两种方式来解决:
1、线程同步(对象锁)来控制
2、通过wait notify来控制
使用synchronized 对方法进行同步化,还可以同步块(同步块只能对对象进行同步)
//单例模式同步化
publicclassUser{
privatestaticUser user;
privateUser(){
}
/**
* 使用synchronized对方法进行同步化
* @return
*/
publicsynchronizedstaticUser getInstance(){
if(user ==null){
//使当前线程暂缓执行
Thread.yield();
user =newUser();
}
return user;
}
}
例子
继承Thread
import java.util.ArrayList;
publicclassArrayListThreadextendsThread{
privateArrayList<Integer> list;
publicArrayListThread(ArrayList<Integer> list){
this.list = list;
}
@Override
publicvoid run(){
//同步块
//同步块中的参数将添加对象锁,使得该对象同一时间只能被一条线程访问
//同步块只能对对象进行同步
synchronized(list){
for(int i =1; i <=10; i++){
//将索引为0的元素的值反复递增1
list.set(0, list.get(0)+1);
}
System.out.println(list.get(0));
}
//同步块执行完毕后将释放对象锁,原本处于锁定状态的对象将允许被其他线程访问
}
}
import java.util.ArrayList;
publicclassRunnableObjectimplementsRunnable{
privateArrayList<Integer> list;
publicRunnableObject(){
list =newArrayList<Integer>();
list.add(0);
}
@Override
publicvoid run(){
synchronized(this){
for(int i =1; i <=10; i++){
//将索引为0的元素的值反复递增1
list.set(0, list.get(0)+1);
}
System.out.println(list.get(0));
}
}
}
publicclassTest{
/**
* @param args
*/
publicstaticvoid main(String[] args){
// TODO Auto-generated method stub
//使用继承Thread的方式实现线程的同步处理
// ArrayList<Integer> list = new ArrayList<Integer>();
// list.add(0);
//
// for(int i = 1; i <= 10; i++){
// ArrayListThread t = new ArrayListThread(list);
// t.start();
// }
//使用Runnable的方式实现线程的同步处理
RunnableObject obj =newRunnableObject();
for(int i =1; i <=10; i++){
Thread t =newThread(obj);
t.start();
}
}
- }
publicclassThread1extendsThread{
privateObject obj;
publicThread1(Object obj){
this.obj = obj;
}
publicvoid run(){
System.out.println("thread1进入到阻塞状态");
//对象在调用wait方法阻塞时必须要对该对象进行同步
synchronized(obj){
try{
//wait的线程只能通过notfiy方法来唤醒
obj.wait();
System.out.println("解除了阻塞状态");
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
publicclassThread2extendsThread{
privateObject obj;
publicThread2(Object obj){
this.obj = obj;
}
publicvoid run(){
synchronized(obj){
System.out.println("唤醒obj对象");
//唤醒该对象
obj.notify();
System.out.println("唤醒结束");
}
}
}
publicclassTest{
/**
* @param args
*/
publicstaticvoid main(String[] args){
Object obj =newObject();
Thread1 t1 =newThread1(obj);
t1.start();
Thread2 t2 =newThread2(obj);
t2.start();
}
}
publicclassUserextendsThread{
privateString name;
//卫生间
privateObject toilet;
publicUser(String name,Object toilet){
this.name = name;
this.toilet = toilet;
}
publicvoid run(){
//判断用户
if(name.equals("tom")){
System.out.println(name+"进入了卫生间,准备上厕所");//1
synchronized(toilet){
System.out.println(name+"正在卫生间,上厕所中……");//2
try{
Thread.sleep(3000);
}catch(InterruptedException e1){
e1.printStackTrace();
}
//使用卫生间的时候,别人无法继续使用,因此需要锁定卫生间
try{
toilet.wait();//3
System.out.println(name+"离开了卫生间");//7
toilet.notify();//8
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
elseif(name.equals("jack")){
System.out.println(name+"准备上卫生间");
synchronized(toilet){
System.out.println(name+"敲门要求卫生间的人出来");//4
toilet.notify();//5
try{
toilet.wait();//6
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(name+"正在使用卫生间,上厕所中");//9
try{
Thread.sleep(3000);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(name+"离开了卫生间");//10
}
}
}
publicstaticvoid main(String[] args){
Object toilet =newObject();
User user1 =newUser("tom", toilet);
User user2 =newUser("jack", toilet);
user1.start();
user2.start();
}
}