多线程
线程与进程的概念
在程序执行过程中,一个应用程序就是一个进程,在这个进行运行过程中可能根据不同的功能创建多个线程
创建线程
创建获取线程的方式有四种,但是常用方式两种
1)继承Thread类重写run方法
2)实现runnable接口实现run方法
jdk1.5以后额外新增两种方法
3)实现callable接口实现call方法
4)线程池创建
继承Thread类重写run方法
public class MyThread extends Thread {
// 创建类继承thread
// 类似于自己为指定任务创建了一个线程类
String name;
public MyThread(String name) {
super();
this.name = name;
}
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println(name + ":" + i);
}
}
public static void main(String[] args) {
// 使用线程类创建完成指定功能的线程对象并调用
MyThread mt = new MyThread("线程1");// 创建线程对象
mt.start();// 启动线程
MyThread mt2 = new MyThread("线程2");// 创建线程对象
mt2.start();// 启动线程
}
}
实现runnable接口实现run方法
//创建实现类实现runnable接口 实现run方法
public class MyRunnable implements Runnable {
// 实现runnable类似于创建的是线程要执行的任务类
// 需要创建线程并将任务交给线程执行
@Override
public void run() {
// 书写要执行的功能
for (int i = 1; i <= 10; i++) {
System.out.println( i);
}
}
public static void main(String[] args) {
//首先创建任务对象
MyRunnable mr=new MyRunnable();//要执行的任务对象
//创建线程并将任务交由线程执行
Thread t=new Thread(mr);
t.start();
Thread t1=new Thread(mr);
t1.start();
}
}
区别
本质上thread也实现了runnable接口,不同的是java中继承为单继承,并且多个对象间不能实现资源的共享.实现runnable接口虽然可以实现资源的共享但是如果多个线程执行不相干不同的任务使用继承thread类的形式有时更简单
使用继承thread类重写run方法的形式实现多个线程售票
public class MyThread extends Thread {
// 创建类继承thread
// 类似于自己为指定任务创建了一个线程类
static int ticket = 5;
// 当前类可以使用static修饰变量的形式实现共享,但是如果多个线程类就不能实现资源的共享了
@Override
public void run() {
while (true) {
if (ticket > 0) {
System.out.println("买票" + ticket--);
} else {
System.out.println("票已售空");
break;
}
}
}
public static void main(String[] args) {
// 使用线程类创建完成指定功能的线程对象并调用
MyThread mt = new MyThread();// 创建线程对象
mt.start();// 启动线程
MyThread mt2 = new MyThread();// 创建线程对象
mt2.start();// 启动线程
}
}
使用实现runnable接口重写run方法的形式实现多线程售票
//创建实现类实现runnable接口 实现run方法
public class MyRunnable implements Runnable {
// 实现runnable类似于创建的是线程要执行的任务类
// 需要创建线程并将任务交给线程执行
int ticket = 5;
@Override
public void run() {
// 书写要执行的功能
while (true) {
if (ticket > 0) {
System.out.println("买票" + ticket--);
} else {
System.out.println("票已售空");
break;
}
}
}
public static void main(String[] args) {
// 首先创建任务对象
MyRunnable mr = new MyRunnable();// 要执行的任务对象
// 创建线程并将任务交由线程执行
//多个不同的线程对象使用的同一个任务对象,所以任务对象中所有属性共享
Thread t = new Thread(mr);
t.start();
Thread t1 = new Thread(mr);
t1.start();
}
}
常用方法
构造方法
Thread(Runnable target)
使用指定任务对象创建线程
Thread(Runnable target, String name)
使用指定任务对象指定名称创建线程
常用方法
String getName()
返回该线程的名称。 如果在创建线程时指定线程名则获取,否则根据创建顺序命名为Thread-0 向后递增
int getPriority()
返回线程的优先级。
void setPriority(int newPriority)
更改线程的优先级。
void setName(String name)
改变线程名称,使之与参数 name 相同。
void start()
使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
static void sleep(long millis)
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
static Thread currentThread()
返回对当前正在执行的线程对象的引用
线程同步(线程安全)
在线程执行时,有可能在进行判断时多个线程使用相同变量进行判断,导致数据的不准确,从而导致最终结果与预期结果不符
多线程同步
多个线程同时运行使用同一资源是对于每个线程同步执行(需要在前一个线程使用完毕后下一个线程才能继续使用)
锁
在多线程同步时定义锁的概念,锁可以是一个对象或一个 方法,在线程执行时获取锁,执行介绍时释放,只有获取锁的线程可以执行否则进入等待
synchronized关键字
线程同步方法
同步代码块
使用同步关键字synchronized进行代码块的修饰,加入相应的对象作为锁
将需要同步执行的代码书写在同步代码块中
synchronized (锁对象) {
需要同步执行的代码块
}
public class SynchronizedTest {
public static void main(String[] args) {
// MyR r = new MyR();
// MyR r1 = new MyR();
// Thread t1 = new Thread(r);
// Thread t2 = new Thread(r1);
// t1.start();
// t2.start();
MyT mt1 = new MyT();
MyT mt2 = new MyT();
mt1.start();
mt2.start();
}
}
class MyR implements Runnable {
int t = 5;
@Override
public void run() {
while (true) {
synchronized (this) {//使用多个线程执行的任务对象当做锁对象
if (t > 0) {
System.out.println(Thread.currentThread().getName() + "正在做第" + t-- + "道题");
} else {
break;
}
}
}
}
}
class MyT extends Thread {
static Integer t = 5;//将数据包装类当做锁对象
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (t) {
if (t > 0) {
System.out.println(Thread.currentThread().getName() + "正在做第" + t-- + "道题");
} else {
break;
}
}
}
}
}
同步方法
使用同步关键字synchronized进行方法的修饰,该方法的对象作为锁
//使用同步方法进行线程的同步
public class ThreadTest1 {
public static void main(String[] args) {
// MyRun mr1 = new MyRun();
// Thread t1 = new Thread(mr1);
// Thread t2 = new Thread(mr1);
// t1.start();
// t2.start();
MyThr mt1 = new MyThr();
MyThr mt2 = new MyThr();
mt1.start();
mt2.start();
}
}
class MyRun implements Runnable {
int t = 5;
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 执行操作
getT();
}
}
// 使用同步关键字修饰方法
public synchronized void getT() {
// 在线程调用该方法是,获取该方法对象作为锁
if (t > 0) {
System.out.println(Thread.currentThread().getName() + "正在做第" + t-- + "道题");
}
}
}
class MyThr extends Thread {
static int t = 5;
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 执行操作
getT();
}
}
public static synchronized void getT() {
// 在线程调用该方法是,获取该方法对象作为锁
if (t > 0) {
System.out.println(Thread.currentThread().getName() + "正在做第" + t-- + "道题");
}
}
}
死锁
当多个线程间使用多个锁资源,互相占用等待对方释放的过程
public class M {
public static void main(String[] args) {
Father f = new Father();
Son s = new Son();
FatherThread ft = new FatherThread(f, s);
SonThread st = new SonThread(f, s);
ft.start();
st.start();
}
}
//父类线程
class FatherThread extends Thread {
Father f;
Son s;
public FatherThread(Father f, Son s) {
super();
this.f = f;
this.s = s;
}
@Override
public void run() {
synchronized (f) {
f.get();
synchronized (s) {
f.set();
}
}
}
}
class SonThread extends Thread {
Father f;
Son s;
public SonThread(Father f, Son s) {
super();
this.f = f;
this.s = s;
}
@Override
public void run() {
synchronized (s) {
s.get();
synchronized (f) {
s.set();
}
}
}
}
class Father {
public void get(){
System.out.println("你给我成绩单,我给你玩具");
}
public void set(){
System.out.println("给你玩具");
}
}
class Son {
public void get() {
System.out.println("你给我玩具,我给你成绩单");
}
public void set() {
System.out.println("给你成绩单");
}
}