Java中的多线程及其安全问题

一、Java中的多线程

1.通过创建实现Runnable接口的类

步骤:
a.创建一个实现了Runnable接口的类
b.重写接口的run()方法
c.实例化实现了Runnable的类
d.实例化Thread的对象,并将c中的类作为构造函数的参数
e.start();

// Runnable
class MyTarget implements Runnable{
    private int num = 10;
    @Override
    public void run() {
        while(true){
            if(num > 0){
                System.out.println(Thread.currentThread().getName() + "---" + num);
                num --;
            }else break;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        MyTarget tar = new MyTarget();
        Thread t1 = new Thread(tar);
        Thread t2 = new Thread(tar);
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
        new Thread(tar).start();//匿名类也可创建线程
    }
}
/*
        Thread-2---10
        Thread-2---9
        Thread-2---8
        线程1---10
        线程2---10
        线程1---6
        Thread-2---7
        线程1---4
        线程2---5
        线程1---2
        Thread-2---3
        线程2---1*/

2.通过创建继承Thread的类

步骤:
a.创建一个继承了Thread的类
b.重写接口的run()方法(Thread也实现了Runnable接口)
c.实例化类
d.start();

//extends
class thread extends Thread{
    private static int num = 10;
    @Override
    public void run() {
        while(true){
            if(num > 0){
                System.out.println(Thread.currentThread().getName() + "---" + num);
                num --;
            }else break;
        }
    }
}
public class Main {
    public static void main(String[] args) {
        thread t1 = new thread();
        thread t2 = new thread();
        t1.setName("线程1");
        t2.setName("线程2");
        new Thread("线程3"){//匿名类创建线程
            @Override
            public void run() {
                for(int i = 0; i < 10; i ++){
                    System.out.println(Thread.currentThread().getName() + "---" + i);
                }
            }
        }.start();
        t1.start();
        t2.start();
    }
}
/*线程1---10
线程1---9
线程1---8
线程1---7
线程3---0
线程3---1
线程2---10
线程3---2
线程1---6
线程1---4
线程1---3
线程1---2
线程3---3
线程2---5
线程3---4
线程3---5
线程3---6
线程1---1
线程3---7
线程3---8
线程3---9*/

3.创建实现Callable接口的类

a.创建一个实现Callable的实现类
b.实现call方法,将此线程需要执行的操作声明在call()方法中
c.创建Callable接口实现类的对象
d.将该对象作为参数传递到FutureTask构造器中,创建FutureTask对象
e.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
f.获取Callable中call方法的返回值b

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class NumThread implements Callable {
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 1; i < 100; i++) {
            if(i % 2 == 0){
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}

public class Call {
    public static void main(String[] args) {
        NumThread numThread = new NumThread();
        FutureTask futureTask = new FutureTask(numThread);
        new Thread(futureTask).start();
        try {
            Object sum = futureTask.get();
            System.out.println(sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

4.使用线程池

a.提供指定线程数量(比如10个)的线程池ExecutorService service = Exectors.newFixedThreaPool(10);
b.执行指定的线程操作。需要提供实现Runnable接口或Callable接口实现类的对象
service.execute(Runnable)/service.submit(Callable)
c.关闭连接池
service.shutdown()

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class NumberThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){
                System.out.println(i);
            }
        }
    }
}

public class ThreadPoll {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);
        service.execute(new NumberThread());
        service.shutdown();
        //service.submit();
    }
}

二、 多线程安全问题的解决

多线程的安全问题多由线程操作共享数据导致。

1.sychronized同步机制

注意:确保是同一个锁

①代码块

synchronized(同步监视器){
    需要被同步的代码:操作共享数据的代码
}
同步监视器:锁,多个线程必须要共用同一把锁,任何类的一个对象都可以充当锁.
使用实现接口的方式中可以用this充当锁
在继承方式中可以使用*.class充当锁
(非必要)

// An highlighted block
class MyTarget implements Runnable{
    private int num = 10;
    @Override
    public void run() {
        while(true){
            synchronized(this){
                if(num > 0){
                    System.out.println(Thread.currentThread().getName() + "---" + num);
                    num --;
                }else break;
            }

        }
    }
}

public class blog {
    public static void main(String[] args) {
        MyTarget tar = new MyTarget();
        Thread t1 = new Thread(tar);
        Thread t2 = new Thread(tar);
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
        new Thread(tar).start();
    }
}
class thread extends Thread{
    private static int num = 10;
    @Override
    public void run() {
        while(true){
            synchronized(thread.class){
                if(num > 0){
                    System.out.println(Thread.currentThread().getName() + "---" + num);
                    num --;
                }else break;
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        thread t1 = new thread();
        thread t2 = new thread();
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();

    }
}

②方法

实现接口方法:
方法名前加synchronized如果操作共享数据的代码完整的声明在一个方法中,可以使用同步方法解决线程安全问题 同步监视器为this
继承方法:
再加static此时同步监视器为*.class

class MyTarget implements Runnable{
    private static boolean flag = true;
    private int num = 10;
    private synchronized void show(){
        if(num > 0){
            System.out.println(Thread.currentThread().getName() + "---" + num);
            num --;
            if(num <= 0) flag = false;
        }
    }
    @Override
    public void run() {
        while(flag){
            show();
        }

    }
}

public class Main {
    public static void main(String[] args) {
        MyTarget tar = new MyTarget();
        Thread t1 = new Thread(tar);
        Thread t2 = new Thread(tar);
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
        new Thread(tar).start();
    }
}
class thread extends Thread{
    private static boolean flag = true;
    private static int num = 1000;
    private static synchronized void show(){
        if(num > 0){
            System.out.println(Thread.currentThread().getName() + "---" + num);
            num --;
            if(num <= 0) flag = false;
        }
    }
    @Override
    public void run() {
        while(flag){
            show();
        }
    }
}
public class Main {
    public static void main(String[] args) {
        thread t1 = new thread();
        thread t2 = new thread();
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
    }
}

2.Lock锁

a创建ReentrantLock类(参数类型boolean,true实现先进先出,默认为false)
b.在需要同步的代码块上使用try…finally结构
c.try里调用lock();
d.finally里调用unlock();

import java.util.concurrent.locks.ReentrantLock;
class Win implements Runnable{
    private int ticket = 100;
    private ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
		while(true){
            try{
                lock.lock();
                if(ticket > 0){
                    System.out.println(Thread.currentThread().getName() + "NO." + ticket);
                    ticket --;
                }else break;
            }finally{
                lock.unlock();
            }
        }
    }
}

public class LockTest {
    public static void main(String[] args) {
        Win w = new Win();
        new Thread(w).start();
        new Thread(w).start();
        new Thread(w).start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值