多线程
线程的创建方法
1)继承Thread类,重写run()方法
class Student extends Thread{
public void run(){
//run方法中的内容就是线程的内容
}
}
在主函数中:
public static void main(String[] args) {
Student s = new Student();//创建一个线程
s.start()//启动线程,注意:不是s.run();
}
2)实现Runnable接口
class Student implements Runnable
//重写run方法
public void run(){
//线程的内容
}
在主函数中:
public static void main(String[] args) {
Student s = new Student();
Thread thread1 = new Thread(s);//创建线程
thread1.start();//启动线程
}
在开发中一般用第二种方法,因为java只允许但继承,而接口却可以多实现,第二种方法更加灵活。
同步代码块 关键字:synchronized
当多个线程公用一个代码块时,有时会出现一些意想不到的错误。如卖票时可能会同时卖出多张一样的票,也可能有的票没有被卖出。这就需要同步代码块。
例如:
synchronized(x){
for(int i =0;i<100;i++){
}
}
在这个代码块中x是一个任意的对象,被称为对象锁,当一个线程竞争到这把锁之后,在它没有执行完这些代码块之前是不会被其它线程运行的,及时抢到了cpu也没用。这就有效的防止了同步问题。
同时还可以用synchronized关键字去定义synchronized函数,这也是一种代码块,只不过它的锁是所在类的对象。
线程中的join方法
join方法是在已有的线程中加入线程,在运行完这个加入的线程之前是不会执行原有的线程的。
代码如下:
主函数:
public class Test5 {
public static void main(String[] args) {
Thread2 s2= new Thread2();
Thread1 s1= new Thread1(s2);
Thread t1 = new Thread(s1);
Thread t2 = new Thread(s2);
t1.start();
System.out.println("主函数结束");
}
}
线程1:
public class Thread1 implements Runnable{
//在一个线程中加入另一个线程的方法
//在加入的线程没有运行完之前是不会执行当前线程的。
private Thread t2;
public Thread1(Thread2 t2){
this.t2 = new Thread(t2);
}
public void run(){
System.out.println("线程一开始");
try {
t2.start();
t2.join();
//t2.join(100);等待这个线程100ms到100ms之后就会与线程2进行竞争cup.
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1结束");
}
}
线程2:
public class Thread2 implements Runnable{
public void run(){
System.out.println("线程2开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2结束");
}
}
当用第二种方式产生线程时的情况:
主函数:
public class Test5 {
public static void main(String[] args) {
Thread2 s2= new Thread2();
Thread1 s1= new Thread1(s2);
Thread t1 = new Thread(s1);
Thread t2 = new Thread(s2);
t1.start();
System.out.println("主函数结束");
}
}
线程1:
public class Thread1 implements Runnable{
//在一个线程中加入另一个线程的方法
//在加入的线程没有运行完之前是不会执行当前线程的。
private Thread t2;
public Thread1(Thread2 t2){
this.t2 = new Thread(t2);
}
public void run(){
System.out.println("线程一开始");
try {
t2.start();
t2.join();
//t2.join(100);等待这个线程100ms
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1结束");
}
}
线程2:
public class Thread2 implements Runnable{
public void run(){
System.out.println("线程2开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2结束");
}
}
wait()和notify()函数。
而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备。由此可见这两个方法主要是在synchronized代码块中或者在synchronized的函数中。当两个代码块共同用同一个对象锁时经常用这两个函数。比如生产者消费者的问题:
引用其他的博客内容:
··············································································································································································································································································································
最近在学习同步的时候用到了这两个方法,开始在学习线程的时候没有注意到wait()和notify方法。原因是这两个方法不属于Thread类,它们是在lang包下面的Object类,是最底层的基础类。因此每个类的对象都可以操作这两个方法。而这两个方法的用途就是操作锁,所以它们只能在synchronized方法或者synchronized块中使用。说道wait()方法,就不得不提到Thread类中的一个静态的方法sleep(),两者间最大的区别在于:sleep()方法在睡眠的时候也一直拿着锁不放开,因此其他的线程也得不到这把锁。而wait()方法在睡眠的时候会放开锁,给其他的线程使用。wait()有两种方式获得锁:1.wait(long timeout),通过设定时间来获得锁,值得注意的是,timeout这个时间到了以后,它不会立即醒来,而是要看那个正在使用这把锁的线程是否结束。2.通过notify()的方法,通知需要这把锁的wait(),使之唤醒,而notifyAll()是通知所有的线程。
·············································································································································································································································································································
代码:
主函数:
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Product product=new Product();
ConsumerThread consumerRun=new ConsumerThread(product);
CreatThread creatRun=new CreatThread(product);
Thread t1=new Thread(consumerRun);
Thread t2=new Thread(creatRun);
t1.start();
t2.start();
}
}
生产者:
public class CreatThread implements Runnable{
private Product product;
public CreatThread(Product product) {
this.product=product;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
product.creat();
}
}
}
消费者:
public class ConsumerThread implements Runnable{
private Product product;
public ConsumerThread(Product product) {
this.product = product;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
product.sumer();
}
}
}
生产和消费的过程:
public class Product {
private boolean isHave = false;
public synchronized void creat() {
if(isHave){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("开始生产");
// try {
// Thread.sleep(3000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println("生产了一件产品");
isHave=true;
notify();
}
public synchronized void sumer() {
System.out.println("消费前");
if (!isHave) {
try {
System.out.println("等待商家生产");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// System.out.println("商家生产完成");
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
//
// e.printStackTrace();
// }
System.out.println("消费完成");
isHave=false;
notify();
}
}
sleep()方法
sleep( )方法可以使线程休眠,例如
sleep(1000)//线程休眠1秒