---------------------- 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培训、期待与您交流! ----------------------