黑马程序员 多线程

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

进程:正在进行中的程序(直译)

线程:就是进程中一个负责程序执行的控制单元(执行路径)

一个进程中可以有多个执行路径,称之为多线程

 

一个进程中至少有要有一个线程。

 

开启多个线程是为了同时运行多部分代码。

 

每一个线程都有自己运行的内容。这个内容可以称为线程要执行的任务。

多线程的好处:解决了多部分同时运行的问题。

多线种的弊端:线程太多回到效率的降低。

 

其实应用程序的执行都是CPU在做着快速的切换完成的。这个切换是随机的。

 

JVM启动时就启动了多个线程,至少有两个线程可以分析的出来。

1, 执行main函数的线程

该线程的任务代码都定义在main函数中。

2, 负责垃圾回收的线程。

 

 

如何创建一个线程呢?

A:方式1 继承Thread类。
a:创建类继承Thread类
b:重写Thread类的run()方法。
run()方法里面才是封装线程的代码。
c:通过调用start()方法启动线程并调用run()方法。


代码体现:
			public class MyThread extends Thread
			{
				public void run()
				{
					for(int x=0; x<100; x++)
					{
						System.out.println(getName()+"---"+"hello"+x);
					}
				}
			}


			public MyThreadTest
			{
				public static void main(String[] args)
				{
					MyThread my1 = new MyThread();
					MyThread my2 = new MyThread();


					my1.start();
					my2.start();
				}
			}






B:方式2 实现Runnable接口
a:创建一个类实现Runnable接口
b:重写run()方法
c:创建实现类对象,并把它作为参数传递给Thread类的构造方法,创建Thread对象
d:通过Thread的对象执行


代码体现:


			public class MyRunnable implements Runnable
			{
				public void run()
				{
					
					for(int x=0; x<100; x++)
					{
						System.out.println(Thread.currentThread().getName()+"---"+"hello"+x);
					}
					
				}
			}


			public class MyRunnableTest
			{
				public static void main(String[] args)
				{
					MyRunnable my = new MyRunnable();


					Thread t1 = new Thread(my);
					Thread t2 = new Thread(my);


					t1.start();
					t2.start();
				}
			}


线程的随机性原理
多个程序其实是CPU的在做着高效切换执行的。
线程的生命周期(面试题 自己补齐)
新建
就绪
运行
阻塞
死亡
线程安全问题
A:卖票案例

/*
 * 目前这个代码是符合真实的卖票程序。
 * 但是,有问题,居然出现了负数票的情况。
 * 那么,产生的原因是什么呢?
 * 		线程的随机性和延迟性,导致了线程访问共享数据出现了问题。
 * 怎么解决呢?
 */
public class TicketRunnable implements Runnable {

	private int tickets = 100;

	@Override
	public void run() {
		while (true) {
			//t1,t2,t3,t4过来了
			//tickets = 1
			if (tickets > 0) {
				//t1首先抢到了CPU的执行权,接着,进行了判断,发现是满足条件的,就进来了
				//t2就抢到了,也进行了判断,发现还是满足,也就进来了
				//t3抢到了,也进行了判断,发现还是满足,也就进来了
				//t4抢到了,也进行了判断,发现还是满足,也就进来了
				// public static void sleep(long millis)
				try {
					//t1睡着了
					//t2睡着了
					//t3睡着了
					//t4睡着了
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//t1醒了 -- 窗口1正在出售第1张票 tickets=0
				//t2醒了 -- 窗口2正在出售第0张票 tickets=-1
				//t3醒了 -- 窗口3正在出售第-1张票 tickets=-2
				//t4醒了 -- 窗口4正在出售第-2张票 tickets=-3
				System.out.println(Thread.currentThread().getName() + "正在出售第"
						+ (tickets--) + "张票");
				
				//注意:如何卖出相同的票的呢?
				//关键点:tickets--
				//A:读取tickets的操作	100
				//B:修改tickets的操作	99
				//C:把最后的值赋值给tickets	= 99
			}
		}
	}

}

public class RunnableTest {
	public static void main(String[] args) {
		TicketRunnable tr = new TicketRunnable();

		Thread t1 = new Thread(tr);
		Thread t2 = new Thread(tr);
		Thread t3 = new Thread(tr);
		Thread t4 = new Thread(tr);

		t1.setName("窗口1");
		t2.setName("窗口2");
		t3.setName("窗口3");
		t4.setName("窗口4");

		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}



B:为什么有问题
a:有共享数据
b:共享数据被多条语句操作
c:在多线程环境中
(6)线程安全问题的解决方案:
A:同步代码块
synchronized(锁对象)
{
被同步的代码
}
B:同步方法
把synchronized加在方法上。


一般推荐使用同步代码块。
(7)线程间的通信问题
学生类:

public class Student {
	String name;
	int age;
}


设置学生属性的类:

public class SetStudent implements Runnable {
	private Student s;

	public SetStudent(Student s) {
		this.s = s;
	}

	@Override
	public void run() {
		int x = 0;
		while (true) {
			if (x % 2 == 0) {
				s.name = "张三";
				s.age = 26;
			} else {
				s.name = "李四";
				s.age = 29;
			}
			x++;
		}
	}

}


获取学生属性的类:

public class GetStudent implements Runnable {
	private Student s;

	public GetStudent(Student s) {
		this.s = s;
	}

	@Override
	public void run() {
		while (true) {
			System.out.println(s.name + "***" + s.age);
		}
	}

}


测试类:

public class StudentTest {
	public static void main(String[] args) {
		Student s = new Student();// 资源类

		SetStudent ss = new SetStudent(s);
		GetStudent gs = new GetStudent(s);

		Thread t1 = new Thread(ss);
		Thread t2 = new Thread(gs);

		t1.start();
		t2.start();
	}
}


(8)常见的方法
优先级
暂停线程
加入线程
守护线程
(9)面试题:
sleep()和wait()的区别?
sleep是线程被调用时,占着cpu去睡觉,其他线程不能占用cpu,os认为该线程正在工作,不会让出系统资源,wait是进入等待池等待,让出系统资源,其他线程可以占用cpu,一般wait不会加时间限制,因为如果wait的线程运行资源不够,再出来也没用,要等待其他线程调用notifyall方法唤醒等待池中的所有线程,才会在进入就绪序列等待os分配系统资源。

启动线程到底调用的是哪个方法?
start()方法是启动(即开辟)一个线程的方法。

run()和start()的区别?
start()方法是启动(即开辟)一个线程的方法,因此线程的启动必须通过此方法, 
而run()方法,只是Thread类的一个方法,它本身并不能开辟线程。 
所以,当你用run()时候,程序只有一个线程,根本没达到你多线程的目的(是错误的)。而你用start()时候,你的程序又开辟了两个线程


同步的原理,以及有几种实现方式?
原理:
在多线程程序中,一般来说,不会是所有的代码都有问题,所以,我们只需要找到那些可能出问题的代码,
  我把可能出问题的代码, 跟包起来,看做是一个整体,只有这个整体完毕,别人才能继续访问。
  为了安全,把这个整体包起来的代码加个锁。给锁起来。

实现方式:
同步代码块
  同步代码块的锁是任意对象。 
 
同步方法:就是把锁加在方法上
  格式:在方法上加synchronized关键字
 
  同步方法的锁对象是谁? this对象
 
静态方法的锁对象是谁呢?
  是当前类的字节码文件对象。
  类名.class - Class类型的对象

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值