一、线程的创建
创建线程有两种方法:
1、继承Thread
定义类并继承类Thread,且重写run方法,启动线程用start;
/**
* @author flame
* 火车票买票小程序,四个窗口同时买票,并保证所买的票不重复
*/
class Ticket extends Thread
{
private static int tick =100;//100张票,共享四个窗口,使其四个窗口所卖出的票不重复(关键点,静态的应用)
public void run()
{
while(tick>0)//使其继续循环
{
if(tick>0)//判断,当票号为零时不打印
{
System.out.println(currentThread().getName()+"--run--"+(tick--));
}
}
}
}
public class TicketDemo {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Ticket t = new Ticket();
Ticket t2 = new Ticket();
Ticket t3 = new Ticket();
Ticket t4 = new Ticket();
t.start();
t2.start();
t3.start();
t4.start();
}
}
2、实现接口Runnable
定义类,实现接口Runnable并重写run方法。
启动线程的方式:
1、通过Thread类建立对象
2、将Runnable接口的之类对象作为实际参数传递给Thread类的构造函数
3、调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
(注:
1、这里之所以要重写run方法,是为了将程序要运行的代码存放在该run方法中。
2、为什么要将Runnable接口的子类对象传递给Thread的构造函数,因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让程序去执行指定对象的run方法。
)
/**
* @author flame
* 火车票买票小程序,四个窗口同时买票,并保证所买的票不重复
*/
class Ticket2 implements Runnable
{
private static int tick =100;//100张票,共享四个窗口,使其四个窗口所卖出的票不重复(关键点,静态的应用)
public void run()
{
while(tick>0)//使其继续循环
{
if(tick>0)//判断,当票号为零时不打印
{
System.out.println("--run--"+(tick--));
}
}
}
}
public class TicketDemo2 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Ticket2 t = new Ticket2();
new Thread(t).start();//把Runnable子类的对象传递给Thread类执行,并启动线程;
}
}
二、线程安全
出现问题的地方(问题原因):
当多条语句在操作同一个线程共享语数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据错误。
解决方法:
对多条操作共享数据的语句,只能让一个进程全部执行完,在执行过程中,其他进程不能参与。
在java中对于多线程安全问题有着专业的解决方式——同步代码块.
synchronized(对象)
{
//要同步的代码
}
synchroized可以用于修饰函数,形成同步函数:
public synchroized void Add()
{
//执行代码
}
(注:synchroized修饰函数时传入的对象是this,修饰静态函数时,传入的对象是类本身。)
按照上面的例子,以下举例:
class Ticket3 implements Runnable
{
private static int tick =100;//100张票,共享四个窗口,使其四个窗口所卖出的票不重复(关键点,静态的应用)
private String name;
Object obj = new Object();
public Ticket3(String name)
{
this.name = name;
}
public void run()
{
while(tick>0)//使其继续循环
{
synchronized (obj) //将同步代码放入同步代码快里面
{
if(tick>0)//判断,当票号为零时不打印
{
System.out.println(name +"--run--"+(tick--));
}
}
}
}
}
三、 死锁
/**
* 死锁举例
* @author flame
*
*/
public class DeadDemo {
/**
* 启动两个线程
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
new Thread(new Dead(true)).start();
new Thread(new Dead(false)).start();
}
}
/**
* 设置两个锁对象
* @author flame
*
*/
class MyLock
{
static Object obja = new Object();
static Object objb = new Object();
}
/**
* 线程D1拿着a锁去要b锁的资源
* 线程D2拿着b锁去要a锁的资源
* 因此形成了死锁
* @author flame
*
*/
class Dead implements Runnable
{
private boolean flag;
public Dead(boolean flag)
{
this.flag = flag;
}
public void run()
{
if(flag)
{
synchronized(MyLock.obja)
{
System.out.println("if obja");
synchronized(MyLock.objb)
{
System.out.println("if objb");
}
}
}
else
{
synchronized(MyLock.objb)
{
System.out.println("else objb");
synchronized(MyLock.obja)
{
System.out.println("else obja");
}
}
}
}
}