GVKun编程网logo

Java_日志接口实现(java接口加日志)

4

想了解Java_日志接口实现的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于java接口加日志的相关问题,此外,我们还将为您介绍关于(JAVA)一个类没有直接实现接口,为什么可以这样为父接口

想了解Java_日志接口实现的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于java接口加日志的相关问题,此外,我们还将为您介绍关于(JAVA) 一个类没有直接实现接口,为什么可以这样为父接口实例化呢?、Java 8 默认接口实现及其他语言特性、Java Lock接口实现原理及实例解析、java 中的接口定义和接口实现的新知识。

本文目录一览:

Java_日志接口实现(java接口加日志)

Java_日志接口实现(java接口加日志)

日志的接口实现:改用slf4j实现日志功能

 

 

为什么要使用slf4j,而不是用log4j或者其他日志框架?

因为slf4j只是规定了一堆实现了日志的接口,并不关心日志怎么实现,这样就可以让项目脱离对日志框架的依赖。

1.下载slf4j.jar包:https://mvnrepository.com/search?q=slf4j,里面包含两个包:slf4j-api.jiar、slf4j-log4j.jar

2.在项目文件夹下新建lib文件夹,将下载好的两个包放入文件夹lib中

3在project structure栏目下的Modules栏的的右侧“+”号中选中lib中添加的两个包,再在project structure下的problems中点击[fix]

4.在src文件下新建log4j.properties,将下面配置文件复制在文件中

 

# priority  :debug<info<warn<error
#you cannot specify every priority with different file for log4j
log4j.rootLogger=debug,stdout,info,debug,warn,error

#console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= [%d{yyyy-MM-dd HH:mm:ss a}]:%p %l%m%n
#info log
log4j.logger.info=info
log4j.appender.info=org.apache.log4j.DailyRollingFileAppender
log4j.appender.info.DatePattern=''_''yyyy-MM-dd''.log''
log4j.appender.info.File=./src/com/lanou/log/info.log
log4j.appender.info.Append=true
log4j.appender.info.Threshold=INFO
log4j.appender.info.layout=org.apache.log4j.PatternLayout
log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
#debug log
log4j.logger.debug=debug
log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender
log4j.appender.debug.DatePattern=''_''yyyy-MM-dd''.log''
log4j.appender.debug.File=./src/com/lanou/log/debug.log
log4j.appender.debug.Append=true
log4j.appender.debug.Threshold=DEBUG
log4j.appender.debug.layout=org.apache.log4j.PatternLayout
log4j.appender.debug.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
#warn log
log4j.logger.warn=warn
log4j.appender.warn=org.apache.log4j.DailyRollingFileAppender
log4j.appender.warn.DatePattern=''_''yyyy-MM-dd''.log''
log4j.appender.warn.File=./src/com/lanou/log/warn.log
log4j.appender.warn.Append=true
log4j.appender.warn.Threshold=WARN
log4j.appender.warn.layout=org.apache.log4j.PatternLayout
log4j.appender.warn.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
#error
log4j.logger.error=error
log4j.appender.error = org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.DatePattern=''_''yyyy-MM-dd''.log''
log4j.appender.error.File = ./src/com/lanou/log/error.log
log4j.appender.error.Append = true
log4j.appender.error.Threshold = ERROR
log4j.appender.error.layout = org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n

 

完成日志框架接口来实现

定义日志属性:

 

final static Logger LOGGER = LoggerFactory.getLogger(ThirdClass.class);

slf4j支持同行记录
String name = "张三";
int age = 12;
String address="大连";
String birthday="1999-3-4";
String id="323456754";


LOGGER.info("我叫:{},今年:{}岁,家住在:{},生日是:{},身份证号是:{}",
name,age,address,birthday,id);
 

 

原文出处:https://www.cnblogs.com/zhouchangyang/p/10589162.html

(JAVA) 一个类没有直接实现接口,为什么可以这样为父接口实例化呢?

(JAVA) 一个类没有直接实现接口,为什么可以这样为父接口实例化呢?

@tcxu 你好,想跟你请教个问题:

package jiu;

interface A { // 定义一个接口
    String INFO = "Hello World .";

    void print (); // 抽象方法
}

interface B { // 定义一个接口
    public abstract void get();
}

abstract class C implements A, B { // 抽象类实现了 A 和 B 接口
    public abstract void fun (); // 抽象方法一共有三个
}

interface D extends A, B { // 同时继承两个接口
    public void printD();
}

class X extends C implements D { // 先继承后实现
    public void print() {
        System.out.println(INFO);
    }

    public void get() {
        System.out.println ("你好!");
    }

    public void fun() {
        System.out.println ("抽象类 C 实现接口 A,B");
    }

    public void printD() {
        System.out.println ("接口 D 继承两个接口 A,B");
    }
}

public class AbstractInterfaces {
    public static void main(String args[]) {
        X x = new X (); // 实例化子类对象
        A a = x; // 为父接口实例化 (引用接口指向实现类,多态)
        B b = x; // 为父接口实例化
        C c = x; // 为抽象类实例化 (引用父类指向子类对象,多态)
        D d = x; // 父接口实现化
        a.print();
        b.get();
        c.fun();
        d.printD();
    }
}

类 X 没有直接实现接口 A 和 B,为什么可以 A a = x; (直接为父接口实例化)呢?这样却不报错,是什么原因呢?

Java 8 默认接口实现及其他语言特性

Java 8 默认接口实现及其他语言特性

一、为什么有默认接口实现

1、由于Java 8的API在现存的接口上引入了非常多的新方法(如List接口上的sort方法)。在原有语法基础上,如Guava和Apache Commons这样的框架都需要修改实现了List接口的所有类。

2、为了解决这个问题,Java 8中的接口现在支持在声明方法的同时提供实现。主要有两种方式:

1)、Java 8允许在接口内声明静态方法。
2)、Java 8引入了一个新功能,叫默认方法,通过默认方法你可以指定接口方法的默认实现。
这种机制可以使你平滑地进行接口的优化和演进

二、冲突解决

我们知道Java语言中一个类只能继承一个父类,但是一个类可以实现多个接口。随着默认方法在Java 8中引入,有可能出现一个类继承了多个方法而它们使用的却是同样的函数签名。这种情况下,类会选择使用哪一个函数?
public interface InterfaceA {
    
    default void hello(){
        System.out.println("Hello from A");
    }

}




public interface InterfaceB extends InterfaceA{

    default void hello(){
        System.out.println("Hello from B");
    }
}



public class ClassC implements InterfaceA,InterfaceB{

    public static void main(String[] args) {
        new ClassC().hello();
    }
}




public class ClassC implements InterfaceA,InterfaceB{

    public static void main(String[] args) {
        new ClassC().hello();
    }
}




result:Hello from B

如果一个类使用相同的函数签名从多个地方(比如另一个类或接口)继承了方法,通过三条规则可以进行判断。
(1) 类中的方法优先级最高。类或父类中声明的方法的优先级高于任何声明为默认方法的优先级。
(2) 如果无法依据第一条进行判断,那么子接口的优先级更高:函数签名相同时,优先选择拥有最具体实现的默认方法的接口,即如果B继承了A,那么B就比A更加具体。
(3) 最后,如果还是无法判断,继承了多个接口的类必须通过显式覆盖和调用期望的方法,

一、重复注解重复注解

二、集合类新增方法集合类新增方法

三、CompletableFutureCompletableFuture

四、ConcurrentHashMapConcurrentHashMap

五、StringString

六、 FilesFiles

七、 精简JRE

Java8提供了三种紧凑的JRE,分别是compact1、compact2、compact3,他们的关系是compact1<compact2<compact3,他们包含的API如下图所示

 精简JRE

八、 删除PermGen space

PermGen space的全称是Permanent Generation space,是指内存的永久保存区域这一部分用于存放Class和Meta的信息。Java8使用本地内存来存储类元数据信息并称之为:元空间( Metaspace),默认情况下,类元数据只受可用的本地内存限制。

删除PermGen space

九、Nashorn

Nashorn

本文作者:魂皓轩 欢迎关注公众号

本人保留所有权益,转载请注明出处。
欢迎有故事、有想法的朋友和我分享,可发送至 e-mail: lwqforit@163.com

Java Lock接口实现原理及实例解析

Java Lock接口实现原理及实例解析

这篇文章主要介绍了Java Lock接口实现原理及实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

1、概述

JUC中locks包下常用的类与接口图如下:

图中,Lock和ReadWriteLock是顶层锁的接口,Lock代表实现类是reentrantlock(可重入锁),ReadWriteLock(读写锁)的代表实现类是reentrantreadwritelock。ReadWriteLock 接口以类似方式定义了读锁而写锁。此包只提供了一个实现,即 reentrantreadwritelock。Condition 接口描述了可能会与锁有关联的条件变量。这些变量在用法上与使用 Object.wait 访问的隐式监视器类似,但提供了更强大的功能。需要特别指出的是,单个 Lock 可能与多个 Condition 对象关联。2、lock与synchronized比较

synchronized是java中的一个关键字,也就是说是Java语言内置的特性。那么为什么会出现Lock呢?

1、Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;

2、Lock和synchronized有一点非常大的不同,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。

synchronized 的局限性与Lock的优点

如果一个代码块被synchronized关键字修饰,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待直至占有锁的线程释放锁。事实上,占有锁的线程释放锁一般会是以下三种情况之一:

1:占有锁的线程执行完了该代码块,然后释放对锁的占有;

2:占有锁线程执行发生异常,此时JVM会让线程自动释放锁;

3:占有锁线程进入WAITING状态从而释放锁,例如在该线程中调用wait()方法等。

下列三种情况:

1 、在使用synchronized关键字的情形下,假如占有锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,那么其他线程就只能一直等待,别无他法。这会极大影响程序执行效率。因此,就需要有一种机制可以不让等待的线程一直无期限地等待下去(比如只等待一定的时间 (解决方案:tryLock(long time, TimeUnit unit))或者能够响应中断(解决方案:lockInterruptibly())),这种情况可以通过 Lock 解决。

2、当多个线程读写文件时,读操作和写操作会发生冲突现象,写操作和写操作也会发生冲突现象,但是读操作和读操作不会发生冲突现象。但是如果采用synchronized关键字实现同步的话,就会导致一个问题,即当多个线程都只是进行读操作时,也只有一个线程在可以进行读操作,其他线程只能等待锁的释放而无法进行读操作。因此,需要一种机制来使得当多个线程都只是进行读操作时,线程之间不会发生冲突。同样地,Lock也可以解决这种情况 (解决方案:reentrantreadwritelock) 。

3、通过Lock得知线程有没有成功获取到锁 (解决方案:reentrantlock) ,但这个是synchronized无法办到的。

上面提到的三种情形,我们都可以通过Lock来解决,但 synchronized 关键字却无能为力。事实上,Lock 是 java.util.concurrent.locks包 下的接口,Lock 实现提供了比 synchronized 关键字更广泛的锁操作,它能以更优雅的方式处理线程同步问题。也就是说,Lock提供了比synchronized更多的功能。

3、Lock接口实现类的使用

// 获取锁

void lock()

// 如果当前线程未被中断,则获取锁,可以响应中断

void lockInterruptibly()

// 返回绑定到此 Lock 实例的新 Condition 实例

Condition newCondition()

// 仅在调用时锁为空闲状态才获取该锁,可以响应中断

boolean tryLock()

// 如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁

boolean tryLock(long time, TimeUnit unit)

// 释放锁

void unlock()

3.1、在Lock中声明了四个方法来获取锁,那么这四个方法有何区别呢?首先,lock()方法是平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他线程获取,则进行等待。在前面已经讲到,如果采用Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此,一般来说,使用Lock必须在try…catch…块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。通常使用Lock来进行同步的话,是以下面这种形式去使用的:

Lock lock = ...; lock.lock(); try{ //处理任务 }catch(Exception ex){ }finally{ lock.unlock(); //释放锁 }

3.2、tryLock() & tryLock(long time, TimeUnit unit)

tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true;如果获取失败(即锁已被其他线程获取),则返回false,也就是说,这个方法无论如何都会立即返回(在拿不到锁时不会一直在那等待)。

tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false,同时可以响应中断。如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。

一般情况下,通过tryLock来获取锁时是这样使用的:

Lock lock = ...; if(lock.tryLock()) { try{ //处理任务 }catch(Exception ex){ }finally{ lock.unlock(); //释放锁 } }else { //如果不能获取锁,则直接做其他事情 }

3.3、lockInterruptibly()

lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果线程 正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。例如,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。

由于lockInterruptibly()的声明中抛出了异常,所以lock.lockInterruptibly()必须放在try块中或者在调用lockInterruptibly()的方法外声明抛出 InterruptedException,但推荐使用后者,原因稍后阐述。因此,lockInterruptibly()一般的使用形式如下:

public void method() throws InterruptedException { lock.lockInterruptibly(); try { //..... } finally { lock.unlock(); } }

注意,当一个线程获取了锁之后,是不会被interrupt()方法中断的。因为interrupt()方法只能中断阻塞过程中的线程而不能中断正在运行过程中的线程。因此,当通过lockInterruptibly()方法获取某个锁时,如果不能获取到,那么只有进行等待的情况下,才可以响应中断的。与 synchronized 相比,当一个线程处于等待某个锁的状态,是无法被中断的,只有一直等待下去。

范例,运行起来后,Thread2能够被正确中断。

public class Test { private Lock lock = new reentrantlock(); public static void main(String[] args) { Test test = new test(); MyThread thread1 = new MyThread(test); MyThread thread2 = new MyThread(test); thread1.start(); thread2.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printstacktrace(); } thread2.interrupt(); } public void insert(Thread thread) throws InterruptedException{ lock.lockInterruptibly(); //注意,如果需要正确中断等待锁的线程,必须将获取锁放在外面,然后将InterruptedException抛出 try { System.out.println(thread.getName()+"得到了锁"); long startTime = System.currentTimeMillis(); for( ; ;) { if(System.currentTimeMillis() - startTime >= Integer.MAX_VALUE) break; //插入数据 } } finally { System.out.println(Thread.currentThread().getName()+"执行finally"); lock.unlock(); System.out.println(thread.getName()+"释放了锁"); } } } class MyThread extends Thread { private Test test = null; public MyThread(Test test) { this.test = test; } @Override public void run() { try { test.insert(Thread.currentThread()); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName()+"被中断"); } } }

3.4 具体的锁实现

Lock的实现类

reentrantlock :即 可重入锁。reentrantlock是唯一实现了Lock接口的类,并且reentrantlock提供了更多的方法。

ReadWriteLock锁:接口只有两个方法:

//返回用于读取操作的锁

Lock readLock()

//返回用于写入操作的锁

Lock writeLock()

ReadWriteLock维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。范例

class ReadWriteLockQueue { //共享数据,只能有一个线程 写数据,但可以多个线程读数据 private Object data = null; private reentrantreadwritelock rwl = new reentrantreadwritelock(); //读数据 public void get() { try { rwl.readLock().lock();//上读锁,其他线程只能读。 System.out.print(Thread.currentThread().getName() + "读取 data!"); Thread.sleep((long) (Math.random() * 1000)); System.out.println(Thread.currentThread().getName() + "读取到的数据:"+ data); } catch (Exception e) { e.printstacktrace(); } finally { rwl.readLock().unlock();//释放读锁 } } //写数据 public void put(Object data) { try { rwl.writeLock().lock();//加上写锁,不允许其他线程 读写 System.out.print(Thread.currentThread().getName() + "写入数据,"); Thread.sleep((long) (Math.random() * 1000)); this.data = data; System.out.println(Thread.currentThread().getName() + "已经写好数据" + data); } catch (Exception e) { e.printstacktrace(); } finally { rwl.writeLock().unlock();//释放锁 } } } public class Testreentrantreadwritelock { public static void main(String[] args) { final ReadWriteLockQueue readWriteLockQueue = new ReadWriteLockQueue(); for (int i = 0; i

4、锁的相关概念

可重入锁 : 如果锁具备可重入性,则称作为 可重入锁 。像 synchronized和reentrantlock都是可重入锁,可重入性在我看来实际上表明了 锁的分配机制:基于线程的分配,而不是基于方法调用的分配。举个简单的例子,当一个线程执行到某个synchronized方法时,比如说method1,而在method1中会调用另外一个synchronized方法method2,此时线程不必重新去申请锁,而是可以直接执行方法method2。

可中断锁:顾名思义,可中断锁就是可以响应中断的锁。在Java中,synchronized就不是可中断锁,而Lock是可中断锁。如果某一线程A正在执行锁中的代码,另一线程B正在等待获取该锁,可能由于等待时间过长,线程B不想等待了,想先处理其他事情,我们可以让它中断自己或者在别的线程中中断它,这种就是可中断锁。在前面演示tryLock(long time, TimeUnit unit)和lockInterruptibly()的用法时已经体现了Lock的可中断性。

公平锁:公平锁即尽量以请求锁的顺序来获取锁。比如,同是有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该所,这种就是公平锁。而非公平锁则无法保证锁的获取是按照请求锁的顺序进行的,这样就可能导致某个或者一些线程永远获取不到锁。在Java中,synchronized就是非公平锁,它无法保证等待的线程获取锁的顺序。而对于reentrantlock 和 reentrantreadwritelock,它默认情况下是非公平锁,但是可以设置为公平锁。

乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

锁主要存在四中状态,依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,他们会随着竞争的激烈而逐渐升级。注意锁可以升级不可降级,这种策略是为了提高获得锁和释放锁的效率。

4.1、偏向锁

引入偏向锁的目的和引入轻量级锁的目的很像,他们都是为了没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。但是不同是:轻量级锁在无竞争的情况下使用 CAS (Compare and Swap)操作去代替使用互斥量。而偏向锁在无竞争的情况下会把整个同步都消除掉。

偏向锁的“偏”就是偏心的偏,它的意思是会偏向于第一个获得它的线程,如果在接下来的执行中,该锁没有被其他线程获取,那么持有偏向锁的线程就不需要进行同步!关于偏向锁的原理可以查看《深入理解Java虚拟机:JVM高级特性与最佳实践》第二版的13章第三节锁优化。

但是对于锁竞争比较激烈的场合,偏向锁就失效了,因为这样场合极有可能每次申请锁的线程都是不相同的,因此这种场合下不应该使用偏向锁,否则会得不偿失,需要注意的是,偏向锁失败后,并不会立即膨胀为重量级锁,而是先升级为轻量级锁。

4.2、 轻量级锁

倘若偏向锁失败,虚拟机并不会立即升级为重量级锁,它还会尝试使用一种称为轻量级锁的优化手段(1.6之后加入的)。轻量级锁不是为了代替重量级锁,它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗,因为使用轻量级锁时,不需要申请互斥量。另外,轻量级锁的加锁和解锁都用到了CAS操作。 关于轻量级锁的加锁和解锁的原理可以查看

《深入理解Java虚拟机:JVM高级特性与最佳实践》第二版的13章第三节锁优化。

轻量级锁能够提升程序同步性能的依据是“对于绝大部分锁,在整个同步周期内都是不存在竞争的”,这是一个经验数据。如果没有竞争,轻量级锁使用 CAS 操作避免了使用互斥操作的开销。但如果存在锁竞争,除了互斥量开销外,还会额外发生CAS操作,因此在有锁竞争的情况下,轻量级锁比传统的重量级锁更慢!如果锁竞争激烈,那么轻量级将很快膨胀为重量级锁!

4.3、自旋锁和自适应自旋锁

轻量级锁失败后,虚拟机为了避免线程真实地在操作系统层面挂起,还会进行一项称为自旋锁的优化手段。

互斥同步对性能最大的影响就是阻塞的实现,因为挂起线程/恢复线程的操作都需要转入内核态中完成(用户态转换到内核态会耗费时间)。

一般线程持有锁的时间都不是太长,所以仅仅为了这一点时间去挂起线程/恢复线程是得不偿失的。 所以,虚拟机的开发团队就这样去考虑:“我们能不能让后面来的请求获取锁的线程等待一会而不被挂起呢?看看持有锁的线程是否很快就会释放锁”。为了让一个线程等待,我们只需要让线程执行一个忙循环(自旋),这项技术就叫做自旋。

何谓自旋锁?它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。

JDK1.6及1.6之后,自旋锁就改为默认开启的了。需要注意的是:自旋等待不能完全替代阻塞,因为它还是要占用处理器时间。如果锁被占用的时间短,那么效果当然就很好了!反之,相反!自旋等待的时间必须要有限度。如果自旋超过了限定次数任然没有获得锁,就应该挂起线程。自旋次数的默认值是10次,但是用户可以修改。

在 JDK1.6 中引入了自适应的自旋锁。自适应的自旋锁带来的改进就是:自旋的时间不在固定了,而是和前一次同一个锁上的自旋时间以及锁的拥有者的状态来决定,虚拟机变得越来越“聪明”了。

4.4、锁消除

锁消除理解起来很简单,它指的就是虚拟机即使编译器在运行时,如果检测到那些共享数据不可能存在竞争,那么就执行锁消除。锁消除可以节省毫无意义的请求锁的时间。

4.5、锁粗化

原则上在编写代码的时候,总是推荐将同步快的作用范围限制得尽量小――只在共享数据的实际作用域才进行同步,这样是为了使得需要同步的操作数量尽可能变小,如果存在锁竞争,那等待线程也能尽快拿到锁。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小编。

java 中的接口定义和接口实现

java 中的接口定义和接口实现

1. 接口的定义

使用 interface 来定义一个接口。接口定义同类的定义类似,也是分为接口的声明和接口体,其中接口体由常量定义和方法定义两部分组成。定义接口的基本格式如下:

[修饰符] interface 接口名 [extends 父接口名列表]{

[public] [static] [final] 常量;
[public] [abstract] 方法;
}
修饰符:可选,用于指定接口的访问权限,可选值为 public。如果省略则使用默认的访问权限。
接口名:必选参数,用于指定接口的名称,接口名必须是合法的 Java 标识符。一般情况下,要求首字母大写。
extends 父接口名列表:可选参数,用于指定要定义的接口继承于哪个父接口。当使用 extends 关键字时,父接口名为必选参数。
方法:接口中的方法只有定义而没有被实现。

例如,定义一个用于计算的接口,在该接口中定义了一个常量 PI 和两个方法,具体代码如下:

注意:
    与 Java 的类文件一样,接口文件的文件名必须与接口名相同。
2. 接口的实现
接口在定义后,就可以在类中实现该接口。在类中实现接口可以使用关键字 implements,其基本格式如下:
[修饰符] class < 类名 > [extends 父类名] [implements 接口列表]{
}
修饰符:可选参数,用于指定类的访问权限,可选值为 public、abstract 和 final。
类名:必选参数,用于指定类的名称,类名必须是合法的 Java 标识符。一般情况下,要求首字母大写。
extends 父类名:可选参数,用于指定要定义的类继承于哪个父类。当使用 extends 关键字时,父类名为必选参数。
implements 接口列表:可选参数,用于指定该类实现的是哪些接口。当使用 implements 关键字时,接口列表为必选参数。当接口列表中存在多个接口名时,各个接口名之间使用逗号分隔。
    在类中实现接口时,方法的名字、返回值类型、参数的个数及类型必须与接口中的完全一致,并且必须实现接口中的所有方法。例如,编写一个名称为 Cire 的类,实现类中定义的接口 CalInterface,具体代码如下:

在类的继承中,只能做单重继承,而实现接口时,一次则可以实现多个接口,每个接口间使用逗号 “,” 分隔。这时就可能出现常量或方法名冲突的情况,解决该问题时,如果常量冲突,则需要明确指定常量的接口,这可以通过 “接口名。常量” 实现。如果出现方法冲突时,则只要实现一个方法就可以了。

我们今天的关于Java_日志接口实现java接口加日志的分享已经告一段落,感谢您的关注,如果您想了解更多关于(JAVA) 一个类没有直接实现接口,为什么可以这样为父接口实例化呢?、Java 8 默认接口实现及其他语言特性、Java Lock接口实现原理及实例解析、java 中的接口定义和接口实现的相关信息,请在本站查询。

本文标签: