一.实现多线程
线程Thread
有name,ID
等属性
使用getName / ID
, setName / ID
等可以实现
//通过继承Thread类实现多线程,两个线程打印A和B
class myThread extends Thread
{
private String mythreadname; //线程名
private int mysleeptime; //休眠时间
private int count; //循环次数
myThread(String s, int m, int c)
{
mythreadname = s;
mysleeptime = m;
count = c;
}
//一定要实现run方法
public void run()
{
try
{ //一定要处理线程中断异常
for (int i=0; i<count; i++)
{
System.out.println(mythreadname + " "+ (i+1));
sleep(mysleeptime);
}
System.out.println(mythreadname + " finished !");
}
catch(InterruptedException e)
{return;}
}
}
public class test
{
public static void main(String args[])
{
myThread threadA = new myThread("Thread A ", 500, 10); //创建线程A
myThread threadB = new myThread("Thread B ", 500, 10);//创建线程B
threadA.start();
threadB.start();
//threadA.run();
//threadB.run();
}
}
这个多线程使两个进程可以一起实现
这个程序中一定要实现run()
函数
函数1
start() :
利用这个函数开启线程
函数2
run():
这个是类Thread
必须要实现的
函数3
sleep():
传入参数是int
,单位是毫秒
并且要使用try-catch
抛出异常,这是java强制要求的
函数4
isAlive():
如果线程被调用,就是true
新建过程中就是`false
函数5
interrupt():
如果有的线程进入休眠状态,我们可以使用这个函数将他唤醒
机制是抛出InterruException
异常
函数6
currentThread()
使用Thread
自己调用,返回的是当前使用CPU的线程对象
实例:
import javax.swing.*;
class ClassRoom implements Runnable
{
Thread student, teacher;
ClassRoom()
{
teacher = new Thread(this); // 强制转换,因为Runnable没有start函数
student = new Thread(this);
teacher.setName("王教授");
student.setName("张三");
}
public void run()
{
// 如果当前的线程是student
if(Thread.currentThread() == student)
{
try
{
System.out.println(student.getName() + "正在睡觉");
Thread.sleep(1000 * 60 * 60); // 会被interrupt函数打断,然后继续执行后面的代码
}
catch(InterruptedException e)
{
System.out.println(student.getName() + "被老师叫醒");
}
System.out.println(student.getName() + "开始听课"); // 这一句不需要抛出异常,会照例继续进行
}
// 当前线程是teacher
else if(Thread.currentThread() == teacher)
{
for(int i = 0; i < 3;i++)
{
System.out.println("上课");
try
{
Thread.sleep(2000);
}
catch (InterruptedException e){}
}
student.interrupt(); // 唤醒student
}
}
}
public class test
{
public static void main(String args[])
{
ClassRoom room = new ClassRoom();
room.student.start();
room.teacher.start();
}
}
- 这个例子中构造函数
teacher = new Thread(this); // 强制转换,因为Runnable没有start函数
student = new Thread(this);
之所以要写成这样,是因为this
实现的Runnable
的接口
这个接口没有start()
函数,没办法进程
-
student
自动调用自己的interrupt
函数,结束自己的slee()
,先执行catch
里面的语句,然后执行后面的语句
如果他没有被打断的话,睡一个小时就开始听课了 -
student
和teacher
是一起进行的,所以可以看到上课和睡觉交替出现
二.锁 synchronized
当一个程序中有共享数据的时候,比如static
修饰的变量时,我们用多个线程去使用这个静态函数,可能会造成歧义。
比如银行,同一个账户,在两个不同的ATM同时取钱
取一次100,那么同时取的话,虽然取了100,但是最后应该账户余额少200
class Cbank{ //银行类
private static int s=1000;
// 可以把synchronized去掉试一下
public static void sub(int m){
int temp=s;
temp=temp-m;
try{
Thread.sleep((int)(1000*Math.random()));
}
catch(InterruptedException e){ }
s=temp;
System.out.println(" s="+s);
}
}
//储户类
class Customer extends Thread{
public void run(){
for(int i=1;i<=5;i++)
Cbank.sub(100);
}
}
//main class
public class test {
public static void main(String args[]){
Customer Customer1= new Customer( );
Customer Customer2= new Customer( );
Customer1.start();
Customer2.start();
}
}
这样最后现实的余额有问题,这个static
使用了和没使用一样
但是我们可以用另一个关键字synchronized
去修饰它,这样在每个线程都是先完全执行完这个被修饰的函数后,别的线程才能调用这个函数