java 多线程随笔( 一)

多线程随笔

最近在准备秋招,看了一些多线程的基础,个人记一下。


线程与进程

简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

java 多线程

java 多线程的实现一般实现Runnable接口,重写run()方法,调用start方法开启线程。多线程最重要解决数据安全问题,所以引入JMM,java内存模型,JMM的关键技术都是围绕多线程的原子性,可见性,有序性的。简单介绍一下吧。

  • 原子性:是指操作的不可中断的,在多线程情况,不被其他线程干扰。
  • 可见性:是指线程修改了共享变量的值,其他线程是马上知道这个修改。
  • 有序性:Happen-Before 规则 详见博客

线程的状态

  • 新建线程:

    start() run() 区别 run只是在当前线程运行,start()创建新的线程 自定义线程实现runnable 接口 重载run ()。

  • 线程终止:

    stop()被废弃了 stop()会立即释放这个线程所只有的锁,会造成数据不一致。
    线程中断:
    Thread.interrupt()设置中断标识位
    Thread.isInterrupted()判断是否被中断 查看检查中断标识
    Thread.interrupted()判断是否被中断 并清除中断标 识

  • 线程让步:

    线程让步,其方法如下:

    static voidyield()

    暂停当前正在执行的线程对象,并执行其他线程
    线程让步用于正在执行的线程,在某些情况下让出CPU资源,让给其它线程执行

  • 线程睡眠:

    sleep() Thread 的方法 
    线程睡眠的过程中,如果是在synchronized线程同步内,是持有         锁(监视器对象)的,也就是说,线程是关门睡觉的,别的线程进不来
    
  • 线程合并: join()
    线程合并是优先执行调用该方法的线程,再执行当前线程

java多线程中的关键字、

  1. synchronized
    其作用是实现线程间的同步。对同步的代码加锁,使每一次,只有一个线程进入同步块。在需要同步的变量,方法和类上加入关键字。
  2. volatile
    volatile是一种弱的同步手段,相对于synchronized来说,某些情况下使用,可能效率更高,因为它不是阻塞的,尤其是读操作时,加与不加貌似没有影响,处理写操作的时候,可能消耗的性能更多些
    列子:
public class Test {
    static volatile int i = 0, j = 0;
    static void one() {
        i++;
        j++;
    }
    static void two() {
        System.out.println("i=" + i + " j=" + j);
    }
    public static void main(String args[]){
        for(int i=0;i<10;i++){
            new Thread() {
                public void run() {
                    one();
                }
            }.start();
        }
        for(int i=0;i<10;i++) {
            new Thread() {
                public void run() {
                    two();
                }
            }.start();
        }
    }

}

运行后发现i与j的值一样
加上volatile可以将共享变量i和j的改变直接响应到主内存中,这样保证了主内存中i和j的值一致性,所以volatile可以保证内存可见性,但是没有原子性
3. lock
Lock是java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作,它能以更优雅的方式处理线程同步问题,例如

public class LockTest {
    public static void main(String[] args) {
        final Outputter1 output = new Outputter1();
        new Thread() {
            public void run() {
                output.output("zhangsan");
            };
        }.start();      
        new Thread() {
            public void run() {
                output.output("lisi");
            };
        }.start();
    }
}
class Outputter1 {
    private Lock lock = new ReentrantLock();// 锁对象
    public void output(String name) {
        // TODO 线程输出方法
        lock.lock();// 得到锁
        try {
            for(int i = 0; i < name.length(); i++) {
                System.out.print(name.charAt(i));
            }
        } finally {
            lock.unlock();// 释放锁
        }
    }
}

这样就实现了和sychronized一样的同步效果,需要注意的是,用sychronized修饰的方法或者语句块在代码执行完之后锁自动释放,而用Lock需要我们手动释放锁,所以为了保证锁最终被释放(发生异常情况),要把互斥区放在try内,释放锁放在finally内。
4. 读写锁:直接上例子

import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

//写和写是互斥的,但是读和读是不需要互斥的
public class ReadWriteLockTest {
    public static void main(String[] args) {
        final Data data = new Data();
        for (int i = 0; i < 3; i++) {
            new Thread(new Runnable() {
                public void run() {
                    for (int j = 0; j < 5; j++) {
                        data.set(new Random().nextInt(30));
                    }
                }
            }).start();
        }
        for (int i = 0; i < 3; i++) {
            new Thread(new Runnable() {
                public void run() {
                    for (int j = 0; j < 5; j++) {
                        data.get();
                    }
                }
            }).start();
        }
    }
}
class Data {
    private int data;// 共享数据
    private ReadWriteLock rwl = new ReentrantReadWriteLock();
    public void set(int data) {
        rwl.writeLock().lock();// 取到写锁
        try {
            System.out.println(Thread.currentThread().getName() + "准备写入数据");
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.data = data;
            System.out.println(Thread.currentThread().getName() + "写入" + this.data);
        } finally {
            rwl.writeLock().unlock();// 释放写锁
        }
    }
    public void get() {
        rwl.readLock().lock();// 取到读锁
        try {
            System.out.println(Thread.currentThread().getName() + "准备读取数据");
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "读取" + this.data);
        } finally {
            rwl.readLock().unlock();// 释放读锁
        }
    }
}

在读数据时,不需要加锁,效率更高


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值