Java学习第十八天--线程

进程:一个正在进行的程序
线程:一个执行路径
        注意:
                1,一个进程中自带一个线程,称为主线程
                2,一个进程中可以有多个线程,称为多线程
                3,除主线程外,都是子线程
                4,线程分为守护线程(后台线程)与前台线程
                5,如果一个进程有前台线程存活,那么程序就不会被销毁.
                6,如果一个进程中所有前台线程都结束,那么进程也将被销毁,此时不管是否有守护线程正在执行
                7,宏观角度来看,线程是同时进行的.从微观角度来说,多个线程交替执行
同步:
        同时只能有一个线程对其进行操作
        线程安全的
异步
        同时可以有多个线程对其进行操作
        线程不安全的

线程的使用

步骤:
        1,创建
        2,使用
创建:
        方案1:创建Thread的子类对象
                方式1:
                        1,创建一个类
                        2,使其继承与Thread
                        3,重写run方法
                        4,创建该类对象,线程对象
                方式2:
                        Thread 线程对象 = new Thread(){
                                重写run方法
                        }
        方式2:将Thread与Runnable分开创建,然后合并使用
                方式1:
                        1,创建一个类
                        2,实现Runnable接口
                        3,重写run方法
                        4,创建该类对象(线程任务对象)
                        5,创建Thread对象,传入线程任务对象
                方式2:
                        Thread 线程对象 = new Thread(new Runnable(){
                                重写run方法
                        });

package com.qf.demo02;

public class Demo02 {

	public static void main(String[] args) throws InterruptedException {
		//方式1
		MyThread myThread01 = new MyThread();
		//方式2
		Thread thread = new Thread() {
			public void run() {	
			}
		};
		
		//方式3
		MyRunnable myRunnable = new MyRunnable();
		Thread thread2 = new Thread(myRunnable);
		
		//方式4
		Runnable runnable = new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
			}
		};
		Thread thread3 = new Thread(runnable);
	}
}

//方式1
class MyThread extends Thread{
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
	}
}

//方式3
class MyRunnable implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		
	}
	
}


使用

1,启动线程
        void start();
                1,开辟新的执行路径(线程)
                 2,此时该线程才会与其他线程抢夺CPU执行权
        注意:线程启动后会执行run方法中的代码
2,线程的休眠
        static void sleep(毫秒)
                注意:
                        1,线程休眠期间不会抢夺CPU执行权
                        2,使用类名调用方法,在那个线程中调用,就让那个线程休眠
练习:在子线程中进行10秒倒计时

package com.qf.demo02;

public class Demo02 {
	public static void main(String[] args) {
		Thread thread = new Thread() {
			public void run() {
				for (int i = 10; i > 0; i--) {
					try {
						Thread.sleep(1000);
						
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(i);
				}
			}
		};
		thread.start();
	}
	
}


3,获取当前线程
        static Thread currentThread();

4,线程名称
        获取线程名称
                String getName()
        设置线程名称
                1,使用setName方法
                        线程对象.setName(线程名称);
                2,在创建线程对象时传入线程名称
                        new Thread(线程任务,线程名称);
                注意:在线程启动前设置
5,线程的优先级
        概念:线程抢夺到CPU执行权的概率(不能做到百分百)
        注意:
                1,取值范围1~10
                2,在线程启动前设置
                3,默认优先级为5
        设置线程优先级
                void setPriority(int newPriority)
        获取优先级
                int getPriority()

6,线程的礼让
        概念:当线程获取到了CPU执行权后,又释放CPU执行权,然后从新抢夺
        方法:
                static void yield()
7,线程的合并
        概念:将多个线程合并为一个线程
        方法:
        void join()
        注意:
                在线程2中使用线程1对象调用该方法,表示将线程1未完成的代码合并到线程2中,此时只要执行完线程1中剩余的代码,才会继续执行线程2剩余的代码
        一般不会自己合并自己
8,守护线程
        设置线程为守护线程:
                void setDaemon(boolean on)
                true:守护线程
                flase:前台线程,默认
注意:当一个进程中所有前台线程执行完毕后,进程将会结束

线程的安全问题

原因:因为多个线程操作同一个数据导致的
解决方法:保证同时只能有一个线程操作
Java如何保证通知只能使用一个线程操作:
        使用synchronized的关键字
        使用:
同步代码块
        语法:
                synchronized(锁对象){
                        要同步的代码
                }
        注意:
                1,保证多个线程使用的锁对象是同一个对象
                2,所有的类的对象都可以作为锁对象
同步方法
        语法:使用synchronized修饰方法
                访问权限修饰符 synchronized 返回值类型 方法名(形参列表){
                        方法体
                }
        注意:
                 谁调用同步方法,谁就是锁对象
同步静态方法
        语法:使用synchronized修饰方法
                访问权限修饰符 synchronized static 返回值类型 方法名(形参列表){
                        方法体
                }
        注意:
                锁对象是同步静态方法所属的类的类对象

练习:

在生活中同时做多个事情,那么在代码就应该用线程描述
案例:
        购买火车票
假设:
        四个窗口:四个线程
        线程任务:买票,票没了就不买了

package com.qf.demo03;

public class MyThread implements Runnable{
	private static int num = 100;
	@Override
	public void run() {
		while (num > 0) {
			suo();
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
	}
	public synchronized void suo() {
		String name = Thread.currentThread().getName();
		if (num <= 0) {
			return;
		}
		num--;
		System.out.println(name+"卖出了一张票,剩余票数为"+num);
	}
	

}
package com.qf.demo03;

public class Demo05 {
	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		Thread thread01 = new Thread(myThread,"窗口一");
		Thread thread02 = new Thread(myThread,"窗口二");
		Thread thread03 = new Thread(myThread,"窗口三");
		Thread thread04 = new Thread(myThread,"窗口四");
		
		thread01.start();
		thread02.start();
		thread03.start();
		thread04.start();
	}
}

线程间的通讯

注意:
        线程间通讯的方法是Object提供的方法
方法:
        休眠
                wait():无限期休眠
                wait(timeout):有限期休眠
                        timeout:休眠时间,单位毫秒
sleep与wait的区别:
        sleep:
                1,是Thread类提供的方法
                2,是静态方法
                3,休眠期间不会释放锁资源
                4,在线程中都可以使用
                5,使用线程对或Thread类名调用

        wait:
                1,是Object类提供的方法
                2,不是静态方法
                3,休眠期间会释放锁资源
                4,只能在同步代码中使用
                5,只能使用当前所在的同步的锁对象调用
        唤醒
                notify():随机唤醒一个正在休眠的线程(参考注意点3)
                notifyAll():唤醒所有正在休眠的线程(参考注意点3)
        注意:
                1,只能在同步代码中使用
                2,只能使用当前所在的同步的锁对象调用
                3,只能唤醒使用该对象使其休眠的线程
                        a锁锁了三线程a1,a2,a3
                        b锁锁了二线程b1,b2
                                a.notifyAll();只能唤醒a1,a2,a3
                                a.notify():随机在a1,a2,a3唤醒一个

案例:
启动两个线程
一个线程打印1~52
一个线程打印A~Z
要求:打印结果为12A34B56C78D...5152Z

package com.qf.demo04;
/*
 * 启动两个线程
一个线程打印1~52
一个线程打印A~Z
要求:打印结果为12A34B56C78D...5152Z
 */
public class Demo04 {
	public static void main(String[] args) {
		String tag = "...";
		Thread thread01 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				for (int i = 1; i < 53; i++) {
					synchronized (tag) {
						System.out.print(i);
						if (i == 52) {
							try {
								tag.wait();//当i=52时,数字输出完毕,数字部分睡眠
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							tag.notify(); //唤醒字母部分
						}else if (i % 2 == 0) {
							tag.notify(); //如果数字为偶数代表两个数输入完毕,唤醒字母部分
							try {
								tag.wait(); //唤醒字母部分后睡眠数字部分
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
					}
				}
				
			}
		});
		thread01.start();
		 
		 Thread thread02 = new Thread(new Runnable() {
			
			@Override
			public void run() {
					for (int i = 65; i < 91; i++) {
						synchronized (tag) {
							try {
								tag.wait(100);//刚开始需要睡眠,保证字母后输出
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							System.out.print((char)i);
								tag.notify(); //输出一个字母唤醒数字
							if (i == 90) {
								try {
									tag.wait(); //如果i=90代表字母输出结束,睡眠字母部分
								} catch (InterruptedException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
							}
					}
				}
				
			}
		});
		 thread02.start();
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值