NIO中获得通道的方式以及线程的实现方式,安全问题,锁

本文介绍了Java NIO获取通道的四种方式,包括FileInputStream、FileChannel、Files类以及Channels类的方法。接着详细阐述了Java中实现线程的三种方式,包括继承Thread、实现Runnable接口和实现Callable接口。还讨论了多线程安全问题,如线程安全的条件、原子性问题以及解决方法,如synchronized和Lock锁。最后提到了线程的死锁现象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这之前首先重复一下获取通道的4种方式

通道:获取通道的方式1

FileInputStream in = new FileInputStream(“a.txt”);
FileOutputStream out = new FileOutputStream(“aa.txt”);
FileChannel 本地的文件传输通道
FileChannel inChannel = in.getChannel();
FileChannel outChannel = out.getChannel();

获取通道方式2

FileChannel inChannel = FileChannel.open(Paths.get(“a.txt”), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get(“bb.txt”), StandardOpenOption.WRITE, StandardOpenOption.CREATE);

获取通道的方式三 JDK1.7 提供了一个类 Files

SeekableByteChannel inChannel = Files.newByteChannel(Paths.get(“a.txt”), StandardOpenOption.READ);
SeekableByteChannel outChannel = Files.newByteChannel(Paths.get(“cc.txt”), StandardOpenOption.WRITE, StandardOpenOption.CREATE);

获取通道的方式4 JDk1.7 有个 Channels

ReadableByteChannel inChannel = Channels.newChannel(new FileInputStream(“a.txt”));
WritableByteChannel outChannel = Channels.newChannel(new FileOutputStream(“dd.txt”));
除此之外,我们还可以直接通过通道传输,代码如下:
直接从输入通道传个输出通道
inChannel.transferTo(0,inChannel.size(),outChannel);
站在输出通道的角度来看
outChannel.transferFrom(inChannel,0,inChannel.size());
接下来我们就开始讲解线程:

线程

Java中的多线程,执行是随机的。因为Java中的线程调度模式是抢占式调度,线程优先级高的优先使用,但这也仅限于可能性。

方式一:extends Thread

让该类继承Thread,重写run方法。然后再在主函数里通过创立该类的对象,再通过对象调方法。

可使用的方法

  1. Thread.sleep();让线程休眠
    MyThread th1 = new MyThread()
  2. join(): 方法可以将多个线程并发的执行,转换成串行。意思就是等待该线程执行完毕了以后, 其他线程才能再次执行
    注意事项:
    在线程启动之后, 在调用方法,如下
    th1.start();
    th1.join();
    3.守护线程
    将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。通俗点来说,就是不管此线程的死活了。
    th1.setDaemon(true);
    th1.start();
    开启方法如上,开启守护线程必须在线程开启前调用。
    4,打断线程的阻塞
    Thread.sleep(1000);
    th1.interrupt();打断线程的阻塞状态,让线程继续运行
    如上,让线程休眠就是让其阻塞的一种现象,此时如果要让线程立马启动,interrupt方法合适。

方式二:implements Runnable(声明实现runnable接口)

让该类实现runnable接口之后实现run方法,再然后让其在创建Thread类时作为参数传递实现,但该方法无法抛出异常,只能抓取,因为接口没抛,子类也不能抛

MyRunable myRunable = new MyRunable();
Thread th = new Thread(myRunable,"线程名称");
  th.start();

方式三:实现 Callable 接口

相较于实现 Runnable 接口的方式,方法可以有返回值,并且可以抛出异常。
实现步骤

  1. 创建一个类实现Callable 接口
  2. 创建一个FutureTask类将Callable接口的子类对象作为参数传进去(执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。FutureTask 是 Future 接口的实现类)
  3. 创建Thread类, 将FutureTask对象作为参数传进去
  4. 开启线程
MyCallable myCallable = new MyCallable();
        FutureTask<Integer> integerFutureTask = new FutureTask<>(myCallable);
        Thread th = new Thread(integerFutureTask);
        th.start();
        //获取线程执行完之后,返回的结果
        Integer integer = integerFutureTask.get();
        System.out.println(integer);

Callable 返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。
Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。

多线程的安全问题

出现线程安全的问题:得符号三个条件
1.是否是多线程环境
2.是否有共享数据
3.是否有多条语句在操作这个共享数据
出现问题3的原因大多是因为原子性所导致(原子性:不可再分割),因为数据操作很快,所以有可能出现多个线程同时操作一个数据的现象。
解决文体的方法,可以通过锁对象的方法

锁对象的方法

1,老式方法

synchronized (锁对象){
            //需要被同步的代码

             }

public class CellRunable implements Runnable {
    static int piao = 100;
   static  Object obj=new Object();
    @Override
    public void run() {
        while (true) {
            synchronized (obj){ //obj 就相当于一把锁 哪个线程一进入同步代码块,就会持有锁,那么这个把所不释放,其他线程就阻塞状态
                if (piao > 0) {
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //i-- i++ 先使用 后运算                                              //th3 //th2 100
                    System.out.println(Thread.currentThread().getName() + "正在售卖 " + (piao--) + " 张票");
                }
            }
            //哪个线程出了同步代码块就会释放锁
        }
    }
}

随意创造一个对象,类,然后通过 synchronized (){代码块} 方法将对象写进去,同时将可能出现多个线程同时操作的数据写入代码块中·。
或者

public static synchronized void maiPiao() {
        //System.out.println(this);
      //  相当于一把锁 哪个线程一进入同步代码块,就会持有锁,那么这个把所不释放,其他线程就阻塞状态
        if (piao > 0) {
            //模拟延迟
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "正在售卖 " + (piao--) + " 张票");
        }
    }

静态同步方法使用的是当前类的字节码文件对象,也就是说你也可以再这个类里再创建一个方法,该方法带有锁,然后通过调方法即可。
2.Lock锁(JDK5以后提供)

static Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true) {
            lock.lock(); //加锁
            if (piao > 0) {
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在售卖 " + (piao--) + " 张票");
            }
            lock.unlock(); //释放锁
        }

死锁

两个或者两个以上的线程, 在抢占CPU的执行权的时候, 都处于等待状态,程序无限运行

 LockeInterface接口
 
public interface LockeInterface {
    //定义两把锁
  public static final  Object objA=new Object();
  public static final  Object objB=new Object();
}


测试区
 MyThread th1 = new MyThread(true);
        MyThread th2 = new MyThread(false);
        th1.start();
        th2.start();

线程区
public class MyThread extends Thread {
    boolean b;
    public MyThread(boolean b) {
        this.b = b;
    }
    @Override
    public void run() {
        if (b) {
            synchronized (LockeInterface.objA) {
                System.out.println("true objA 进来了");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (LockeInterface.objB) {
                    System.out.println("true objB 进来了");
                }
            }
        } else {
            synchronized (LockeInterface.objB) {
                System.out.println("false objB 进来了");
                synchronized (LockeInterface.objA) {
                    System.out.println("false objA 进来了");
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值