Java学习总结——多线程编程

Java多线程编程

一、创建线程的方法一:

继承:extends Thread 重写run()方法

举个栗子:

public class MyThread extends Thread {
public MyThread() {
//空的构造方法
}

//传递name表示线程名字
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (interrupted()) {
System.out.println("释放资源!");
break;
}
System.out.println(getName()+":"+i);
}
}
}
MyThread t1 = new MyThread(“线程一”);
MyThread t2 = new MyThread(“线程二”);
Thread thread = new Thread();
thread.start();//启动线程
thread.getPriority();//获取优先级
thread.setPriority();//设置优先级(1-10)
thread .getName();//获取线程名字
thread .setName();//设置线程名字

线程休眠:

Thread.sleep(4000);//主线程休眠四秒之后再运行

线程加入:

t1.join();//将线程t1加入主线程

设置守护线程:

t2.setDaemon(true);将t2线程设置为守护线程(守护线程需要在线程启动之前设置),守护线程是为守护其他线程而存在,如果其他所有线程都运行完之后,只还剩下守护线程没运行完,那么守护线程将自动销毁!

线程的中断:

t1.interrupt();//手动处理线程中断
interrupted();//将返回布尔值

线程的生命周期:



二、创建线程的方法二:

实现Runnable接口: implement Runnable

public class RunnableThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
Thread thread = Thread.currentThread();//获取当前线程名字
System.out.println(thread.getName()+":"+i);
}

}
}

该方法不能直接使用start()方法启动线程。 需要使用Thread声明一个对象,再将runnable对象传入Thread对象。

RunnableThread t = new RunnableThread();
Thread t1 = new Thread(t,”线程一”);
t1.start();

Thread t2 = new Thread(t,”线程二”);
t2.start();

两种创建线程方法区别: runnable方法只需要创建一个runnable对象,Thread方法需要创建多个MyThread对象。Thread方法获取线程其他参数更方便。两种方法都需要重写run()方法。

使用Runnable方法创建线程的好处:

  1. 可以很方便的实现多线程数据的共享。
  2. 该方法还可以继承其他的类,而继承Thread类的方法不能再继承其他的类了。

三、创建线程的方法三:

匿名内部类

直接在主类里面定义一个Runnable类来实现Runnable接口里面的run()方法。

适用于该线程在主类里面只使用一次的情况,不用再创建一个线程类来实现Runnable接口。

线程安全问题

当多个线程需要同时修改同一共享数据时,产生冲突,就会出现线程安全问题。

  1. 加锁解决:
private Object lock = new Object();//需要声明一个对象作为锁
//加锁
synchronized (lock) {
//需要加锁执行的代码
}//执行完毕,归还钥匙

也可以直接使用同步方法:sellTicket()

public synchronized void sellTicket(){
//需要加锁的代码
}//相当于给这个方法加了锁

同步方法不需要再声明一个对象作为锁了。

  1. 使用专门的锁对象ReentrantLock来加锁:
private ReentrantLock lock = new ReentrantLock();
lock.lock();//加锁
//需要加锁的代码
lock.unlock();//解锁

死锁问题的解决:

多个线程以相同的顺序去取锁,取到所有锁之后才执行需要加锁的代码!

举个栗子:

public class DeadLock {
//创建两把锁
public static Object lock1 = new Object();
public static Object lock2 = new Object();

public static void main(String[] args) {
//启动两个线程
new Thread(new Thread1()).start();
new Thread(new Thread2()).start();
}
}
//匿名内部类实现Runnable创建Thread1线程
class Thread1 implements Runnable{

@Override
public void run() {
synchronized (DeadLock.lock1) {//先取第一把锁
System.out.println("Thread1取得了第一把锁之后要做的事情");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (DeadLock.lock2) {//再取第二把锁
System.out.println("Thread1同时取得两把锁之后要做的事情");
}
}
}

}
//匿名内部类实现Runnable创建Thread2线程
class Thread2 implements Runnable{
@Override
public void run() {
synchronized (DeadLock.lock1) {//先取第一把锁
System.out.println("Thread2取得了第二把锁之后要做的事情");
synchronized (DeadLock.lock2) {//再取第二把锁
System.out.println("Thread2同时取得两把锁之后要做的事情");
}
}
}

}



创建线程组:ThreadGroup

ThreadGroup tg = new ThreadGroup(“我的线程组”);

定时器:Timer

需要在计时器任务里面设置任务:TimerTask

Timer timer = new Timer();//定时器
timer.schedule(new MyTimer(), 2000);//2s后启动计时器任务
timer.schedule(new MyTimer(), 2000, 1000);//2s启动后,隔3s后再重复执行计时器任务
timer.cancel();//取消定时器

举个栗子:

public class Demo_Timer {
public static void main(String[] args) {
Timer timer = new Timer();//定时器

//timer.schedule(new MyTimer(), 2000);
timer.schedule(new MyTimer(), 2000, 1000);
//timer.cancel();//取消定时器

}
}
//定时器任务(匿名内部类)
class MyTimer extends TimerTask{
@Override
public void run() {
System.out.println("定时器任务..");
}

}



四、综合实例:

电影院售票问题: 说明:两种买票方式,手机APP端和电影院窗口端同时售票,采用创建多线程的方式来解决电影票多端售出产生的冲突!

采用实现Runnable接口的方法创建线程。

1、创建AppThread类:(APP端线程类)

public class AppThread implements Runnable {

private Object lock;

public AppThread(Object lock) {

this.lock = lock;

}

@Override

public void run() {

while (MovieTicketManage.count>0) {

synchronized (lock) {

if (MovieTicketManage.count>0) {

System.out.println(Thread.currentThread().getName()+"售出了第"+MovieTicketManage.count+"张电影票..");

MovieTicketManage.count--;

}

}

try {

Thread.sleep(0);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

2、创建WindowThread类:(window端线程类)

public class WindowThread implements Runnable {
private Object lock;

public WindowThread(Object lock) {
this.lock = lock;
}

@Override
public void run() {
while (MovieTicketManage.count>0) {
synchronized (lock) {
if (MovieTicketManage.count>0) {
System.out.println(Thread.currentThread().getName()+"售出了第"+MovieTicketManage.count+"张电影票..");
MovieTicketManage.count--;
}
}

try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}
}

3、创建MovieTicketManage类:(票管理类,存储电影票数量,为了多线程数据的共享)

public class MovieTicketManage {
public static int count = 100;
}

4、创建CinemaSale主类:(电影票售票主类)

public class CinemaSale {
public static void main(String[] args) {
Object lock = new Object();

WindowThread windowThread = new WindowThread(lock);
AppThread appThread = new AppThread(lock);

new Thread(windowThread,"窗口").start();
new Thread(appThread,"APP手机").start();
}
}

需要创建一把相同的锁lock,将这把锁传入AppThread和WindowThread线程类,保证锁的唯一,如果在AppThread线程和WindowThread线程里面创建锁,那么就是不同对象的锁了。就不能保证共享数据的同步,通过定义一个成员变量lock,通过构造方法将这个锁传递过来.



这样在购买电影票的时候就不会产生线程冲突和死锁问题了!

发表评论
留言与评论(共有 0 条评论)
   
验证码:

相关文章

推荐文章

'); })();