多线程
什么是多线程
进程:一个程序执行的过程。
线程:一个程序中包含的独立运行的任务过程为线程。
多线程:一个进程中,可移植性多个任务流程,我们称之为多线程。
多线程的创建与使用
线程创建有两种方式,第一种是继承Thread类,另一种是实现Runnable接口,先介绍第一种。
1、继承java.langa.Thread类
第一步,编写类继承Thread类;
第二步,重写run方法,定义该线程要执行的代码;
第三步,创建线程对象,调用start()方法启动线程。
例子:
Mythread类
public class Mythread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
}
test测试类
public class test {
public static void main(String[] args) {
Mythread mythread = new Mythread();
mythread.start();
}
}
2、实现java.lang.Runnable接口
第一步,创建线程类实现Runnable接口;
第二步,创建接口实现类对象,然后创建Thread线程对象,
第三步,通过线程对象来调用start方法,启动线程。
案例:
Runnable实现类
public class Mythread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
}
test测试类
public class test {
public static void main(String[] args) {
Mythread mythread = new Mythread();
Thread thread=new Thread(mythread);
thread.start();
}
}
3、两种方式的区别
继承Thread方式,代码写法简单,但是耦合度较高,不能在继承其他类。
实现Runnable接口,代码写法相对复杂,但是耦合度低,可以继承其他类。
线程阻塞方法
1、Thread.sleep方法。
public static native void sleep(long millis)
通过让线程休眠来造成线程阻塞,当休眠一段时间后线程自动执行。
案例:
public class Mythread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
if (i==3) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
test测试
public class test {
public static void main(String[] args) {
Mythread mythread = new Mythread();
Thread thread=new Thread(mythread);
thread.start();
}
}
当调用sleep方法休眠时,不会立即执行线程,二十在休眠一定时间后继续执行该线程。
2、join方法
public final void join()
当前线程等待调用join方法的线程执行完毕后再继续执行。
案例:
线程一:
public class Mythread1 extends Thread{
Thread t;
public Mythread1(Thread t) {
this.t=t;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"="+i);
if (i==3) {
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
线程二:
public class Mythread2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"="+i);
}
}
}
test测试类
public class test {
public static void main(String[] args) {
Mythread2 mythread2=new Mythread2();
Thread t2=new Thread(mythread2);
t2.start();
Mythread1 t1=new Mythread1(t2);
t1.start();
}
}
线程同步问题
在网上也看到过很多线程同步的案例,都差不多,线程同步的作用是为了保证数据的一致性
我们都在网上看过关于买火车票的小案例,讲的就是同步,当多个窗口卖票的时候,假如只剩一张票,但此时多个窗口都有人卖票,name票会卖给谁呢,这是就会出现数据不一致的结果,那么怎么解决这个问题呢,很简单,让他们保持数据一致,但是不允许同时操作,限制了同时买票,那么就不会出现数据不一致的问题了。
下面我来举一个银行存取钱的简单小例子。
案例:
关键代码加同步关键词
Account账户类:
public class Account {
private String cardID;
private String name;
private String password;
private double balance;
public Account() {
// TODO Auto-generated constructor stub
}
public Account(String cardID, String name, String password, double balance) {
super();
this.cardID = cardID;
this.name = name;
this.password = password;
this.balance = balance;
}
public String getCardID() {
return cardID;
}
public void setCardID(String cardID) {
this.cardID = cardID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public double getBalance() {
return balance;
}
public void setBalance(double balnace) {
this.balance = balance;
}
@Override
public String toString() {
return "Account [cardID=" + cardID + ", name=" + name + ", password=" + password + ", balnce=" + balance + "]";
}
//同步代码块,重点
public synchronized void getMoney(double money) {
for (int i = 0; i < 10; i++) {
System.out.println("取之前:"+balance);
if (this.balance>=money) {
this.balance-=money;
System.out.println("取之后:"+balance);
}
}
}
}
取钱线程一:
public class Thread1 extends Thread{
Account account;
public Thread1(Account account) {
this.account=account;
}
@Override
public void run() {
account.getMoney(100);
}
}
取钱线程二:
public class Thread2 extends Thread{
Account account;
public Thread2(Account account) {
this.account=account;
}
@Override
public void run() {
account.getMoney(100);
}
}
线程对线类;
public class AccountTest {
public static void main(String[] args) {
Account account=new Account("001", "zhangsna", "123456", 10000);
Thread1 t=new Thread1(account);
t.start();
Thread2 t2=new Thread2(account);
t2.start();
}
}
死锁问题
(1)死锁:线程同步的过程中,各自拿着一把锁不释放,同时又想要使用对方的锁。互相等待对方释放锁。
(2)解决方案:乙方先释放自己拥有的锁,然后等待另一方用完再获取锁执行
锁对象.wait()
锁对象.notify()
锁对象.notifyAll()
这些方法必须在锁对象内部使用。
案例:
线程一:
public class Thread1 extends Thread{
Object a;
Object b;
public Thread1() {
// TODO Auto-generated constructor stub
}
public Thread1(Object a,Object b) {
this.a=a;
this.b=b;
}
@Override
public void run() {
synchronized (a) {
System.out.println("这是a的a");
try {
a.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (b) {
System.out.println("这是a的b");
}
}
}
}
线程二:
public class Thread2 extends Thread{
Object a;
Object b;
public Thread2() {
// TODO Auto-generated constructor stub
}
public Thread2(Object a,Object b) {
this.a=a;
this.b=b;
}
@Override
public void run() {
synchronized (b) {
System.out.println("这是b的b");
synchronized (a) {
System.out.println("这是b的a");
a.notify();
}
}
}
}
死锁test测试类:
public class SISuoTest {
public static void main(String[] args) {
Object a=new Object();
Object b=new Object();
Thread1 thread1 = new Thread1(a, b);
Thread2 thread2 = new Thread2(a, b);
thread1.start();
thread2.start();
}
}