/*
进程:是一个正在执行的程序
每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或叫一个控制单元
线程:就是进程中的一个独立的控制单元
线程在控制进程的执行,一个或多个线程在进程中运行,是最小单位
一个进程中至少有一个线程
java VM 启动的时候有一个进程为java.exe
负责执行java程序的线程,为主线程
扩展:jvm启动不止一个线程,还有负责垃圾回收机制的线程
-----------
如何在自定义的代码中,定义一个线程
创建线程的第一种方式:继承Thread类
1.定义类继承Thread
2.复习Thread类中的run方法
目的:将自定义代码存储在run方法中,让线程运行
3.调用线程的start方法,该方法的两个作用:启动线程,调用run方法
static Thread currentThread():获取当前线程对象
getName():获取线程名称
设置线程名称:setName或者构造函数
*/
//创建两个线程,和主线程交替运行
class Test extends Thread//继承Thread
{
//private String name;
Test(String name)//设置线程的名称
{
//this.name = name;
super(name);//可以直接调用父类方法
}
public void run()//覆盖run方法
{
for(int i=0;i<60;i++)
{
//Thread.currentThread()获取线程的对象 getName()获取该线程的名称
System.out.println(Thread.currentThread().getName()+"....run..."+i);
//System.out.println(name+"...@run...."+i);
}
}
}
class ThreadDemo
{
public static void main(String[] args)
{
Test t1 = new Test("one");
Test t2 = new Test("two");
t1.start();//开启线程并执行run方法
t2.start();
//t1.run();//不写start,就相当于调用run方法,线程没开启,t1.run()没执行完不会执行t2.run()
//t2.run();
for(int i=0;i<60;i++)
{
System.out.println("hello..."+i);
}
}
}
/*
需求:简单的卖票程序
多个窗口同时买票
创建线程的第二种方式:实现Runnable接口
步骤
1.定义类实现Runnable接口
2.覆盖Runnable接口中的run方法
将线程要运行的代码放在该run方法中
3.通过Thread类建立线程对象
4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
为什么要将Runnable接口的子类对象传递给Thread类的构造函数?
因为,自定义的run方法所属的对象是Runnable接口的子类对象
所以要让线程去指定特定对象的run方法,就必须明确该run方法所属的对象
5.调用Thread类的start方法开启线程并调用Runnable接口子类中的run方法
实现方式和继承方式的区别:
实现方式好处:避免了单继承的局限性
在定义线程时,建立使用实现方式
两种方式的区别:
继承Thread:线程代码存放Thread子类run方法中
实现Runnable,线程代码存在接口的子类的run方法
*/
class Ticket implements Runnable
{
private int tick = 100;
public void run()
{
while(true)
{
if(tick>0)
System.out.println(Thread.currentThread().getName()+"..."+tick--);
}
}
}
class ThreadDemo2
{
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);
t1.start();
t2.start();
t3.start();
}
}
/*
多线程的运行出现了安全问题
问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,
还没有执行完,另外一个线程参与进来执行,导致共享数据错误
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行
java对于多线程的安全问题了解决方式
同步代码块
synchronize(对象)
{
需要被同步的代码
}
对象就像锁,持有锁的线程可以在同步中执行
没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁
同步的前提:
1.必须要有两个或者两个以上的线程
2.必须是多个线程使用同一个锁
必须保证同步中只有一个线程在运行
好处:解决了多线程的安全问题
缺点:多个线程需要判断锁,较为消耗资源
*/
class Ticket implements Runnable
{
private int tick = 100;
Object obj = new Object();
public void run()
{
while(true)
{
synchronized(obj)//同步代码块,不加上就会出现票号为负数的情况
{
if(tick>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"..."+tick--);
}
}
}
}
}
class ThreadDemo3
{
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);
t1.start();
t2.start();
t3.start();
}
}
/*
需求:
银行有一个金库
有两个储户分别存300元,每次存100,存3次
目的:该程序是否有安全问题,如果有,如果解决
如何找问题
1.明确哪些代码是是多线程运行代码
2.明确共享数据
3.明确多线程运行代码中,哪些语句是操作共享数据的
*/
class Bank
{
private int sum;//共享数据
Object obj = new Object();
public void add(int n)//多线程运行代码
{
synchronized(obj)
{
sum = sum + n;//操作共享数据的
try
{
Thread.sleep(10);
}
catch (Exception e)
{
}
System.out.println("sum="+sum);//操作共享数据的
}
}
}
class Cus implements Runnable
{
private Bank b = new Bank();//共享数据
public void run()//多线程运行代码
{
for(int x = 0; x < 3; x++)//这里不用加同步,如果加了那么就只能让这个线程运行玩三次循环,就能轮到下一个线程了
{
b.add(100);//操作共享数据的
}
}
}
class ThreadDemo4
{
public static void main(String[] args)
{
Cus c = new Cus();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
黑马程序员_多线程(上)
最新推荐文章于 2024-01-17 09:45:23 发布