多线程简单问题描述

什么是多线程

进程:一个程序执行的过程。
线程:一个程序中包含的独立运行的任务过程为线程。
多线程:一个进程中,可移植性多个任务流程,我们称之为多线程。

多线程的创建与使用

线程创建有两种方式,第一种是继承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();
	}
}

版权声明:本文为qq_43803695原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。