package cn.tedu.thread;
//本类用于多线程编程实现方案1:继承Thread类的方式来完成
public class TestThread1 {
public static void main(String[] args) {
/*4.new对应的是线程的新建状态*/
/*5.要想模拟多线程,至少得启动2个线程
* 如果只启动一个线程,是单线程程序*/
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
MyThread t4 = new MyThread();
/*6.这个run()如果直接这样调用,是没有多线程抢占执行的效果的
* 这个写法只是把代码看做是普通方法来调用,谁先调用,谁先执行*/
// t1.run();
// t2.run();
// t3.run();
// t4.run();
/*7.start()对应的状态就是就绪状态,会把刚刚新建好的线程加入到就绪队列之中
* 至于这个线程什么时候执行,这就是多线程执行的随机性,需要等待OS选中并分配CPU*/
/*8.线程的执行具有随机性,也就是说t1-t4具体怎么执行
* 取决于CPU的调度与时间片的分配,我们是决定不了的*/
/*9.执行start()时,底层会自动调用我们重写的,包含自己业务的run()*/
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class MyThread extends Thread{
/*1.多线程编程实现方案1:继承Thread类+重写run()*/
@Override
public void run() {
/*2.super.run()表示的是调用父类的业务
* 我们现在想用自己的业务,所以注释掉*/
//super.run();
for (int i = 0; i < 10; i++) {
/*3.getName()表示可以获取当前正在执行的线程名称
* 由于本类继承了Thread类,所以可以直接使用Thread类的这个方法*/
System.out.println(i+"="+getName());
}
}
}
package cn.tedu.thread;
//本类用于多线程编程实现方案2:实现Runnable接口来完成
public class TestThread2 {
public static void main(String[] args) {
//目标业务类对象
MyRunnable target = new MyRunnable();
/*如何以多线程的方式启动线程,需要调用start()
* 自己没有,需要与Thread类建立联系:Thread(Runnable target)
* 但是由于Runnable是接口,无法实例化,我们可以把接口实现类对象
* 也就是我们的自定义类的对象作为构造函数的参数传入,与Thread类建立联系*/
Thread t1 = new Thread(target);
Thread t2 = new Thread(target);
Thread t3 = new Thread(target);
Thread t4 = new Thread(target);
t1.start();
t2.start();
t3.start();
t4.start();
StringBuilder s = new StringBuilder();
s.append(s);
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 30; i++) {
/*问题:自定义父类与父接口Runnable中都没有获取线程名字的方法
* 所以还需要从Thread类中找:
* currentThread():静态方法,获取当前正在执行的线程对象
* getName():非静态方法,有刚刚获取到的线程对象调用,返回当前线程对象的名字*/
System.out.println(i+"="+Thread.currentThread().getName());
}
}
}
package cn.tedu.tickets;
/*需求:设计多线程模型,4个售票窗口共计售票100张
* 本方案使用多线程编程实现方案2:实现Runnable接口的方式来完成*/
public class TestRunnable {
public static void main(String[] args) {
TicketRunnable target = new TicketRunnable();
Thread t1 = new Thread(target);
Thread t2 = new Thread(target);
Thread t3 = new Thread(target);
Thread t4 = new Thread(target);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class TicketRunnable implements Runnable{
/*由于自定义类对象,作为唯一的业务对象,只new了一次
* 所以发布的任务,也就是票数天然的会被所有线程对象共享,无需设置为静态也只有一份*/
int ticket = 100;
@Override
public void run() {
while(true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(ticket<=0) break;
System.out.println(Thread.currentThread().getName() + "=" + ticket--);
}
}
}
package cn.tedu.tickets;
/*需求:设计多线程模型,4个售票窗口共计售票100张
* 本方案使用多线程编程实现方案1:继承Thread类的方式来完成*/
public class TestThread {
public static void main(String[] args) {
TicketThread t1 = new TicketThread("窗口一");
TicketThread t2 = new TicketThread("窗口二");
TicketThread t3 = new TicketThread("窗口三");
TicketThread t4 = new TicketThread("窗口四");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class TicketThread extends Thread{
/*问题:4个线程对象共计售票400张,原因是创建了4个本类对象,鸽子操作鸽子的成员变量
* 解决:让所有对象共享同一个变量,这个变量需要设置为静态的*/
static int tickets = 100;
/*添加本类的含餐构造,用于给线程对象起名字
* 由于只添加了这一个含参构造,默认的无参构造被覆盖掉了*/
public TicketThread(String name) {
/*表示调用父类的含参构造,因为实际上起名的功能是父类完成的
* 所以我们需要将本构造函数接到的名字参数,传给父类的构造函数,让父类起名字*/
super(name);
}
@Override
public void run() {
while(true){
/*让每个线程经历休眠,增加线程状态切换的频率与出错的概率,产生了问题
* 问题1:产生了重卖的现象:同一张票卖给了多个人
* 问题2:产生了超卖的现象:超出了规定的票数,出现了0 -1 -2这样的票*/
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+"="+tickets--);
if (tickets<=0) break;
}
}
}