Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Java_4sem.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
<orderEntry type="library" name="Maven: org.hamcrest:hamcrest-all:1.3" level="project" />
<orderEntry type="library" name="Maven: junit-addons:junit-addons:1.4" level="project" />
<orderEntry type="library" name="Maven: xerces:xercesImpl:2.6.2" level="project" />
<orderEntry type="library" name="Maven: xerces:xmlParserAPIs:2.6.2" level="project" />
</component>
</module>
78 changes: 78 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>ru.spbau.mit</groupId>
<artifactId>assignments</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>assignments</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>junit-addons</groupId>
<artifactId>junit-addons</artifactId>
<version>1.4</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<compilerArgs>
<arg>-Xlint:all</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.5.201505241946</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>deafult-report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>deafult-check</id>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
7 changes: 7 additions & 0 deletions src/main/java/ru/spbau/mit/FactoryFromSupplier.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ru.spbau.mit;

import java.util.function.Supplier;

public interface FactoryFromSupplier {
<T> Lazy<T> createLazy(Supplier<T> supplier);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Используется только в тестах, значит только там и должен жить )

5 changes: 5 additions & 0 deletions src/main/java/ru/spbau/mit/Lazy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ru.spbau.mit;

public interface Lazy<T> {
T get();
}
66 changes: 66 additions & 0 deletions src/main/java/ru/spbau/mit/LazyFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package ru.spbau.mit;

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.function.Supplier;

public class LazyFactory<T> {
public static <T> Lazy<T> createLazyOneThread(final Supplier<T> supplier) {
return new Lazy<T>() {
private boolean isCalled = false;
private T result;

public T get() {
if (!isCalled) {
result = supplier.get();
isCalled = true;
}
return result;
}
};
}

public static <T> Lazy<T> createLazyMultiThread(final Supplier<T> supplier) {
return new Lazy<T>() {
private volatile boolean isCalled = false;
private volatile T result;

public T get() {
if (!isCalled) {
synchronized (this) {
if (!isCalled) {
result = supplier.get();
isCalled = true;
}
}
}
return result;
}
};
}

private static class LockFreeLazy<T> implements Lazy<T> {
private volatile T result;
private volatile Supplier<T> supplier;
private static final AtomicReferenceFieldUpdater<LockFreeLazy, Object> updater =
AtomicReferenceFieldUpdater.newUpdater(LockFreeLazy.class, Object.class, "result");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

имена констант пишутся капсом


public LockFreeLazy(Supplier<T> supp) {
supplier = supp;
}


public T get() {
Supplier<T> supp = supplier;
if (supp != null) {
if (updater.compareAndSet(this, null, supp.get())) {
supplier = null;
}
}
return result;
}
}

public static <T> Lazy<T> createLazyMultiThreadLockFree(Supplier<T> supplier) {
return new LockFreeLazy<T>(supplier);
}
}
195 changes: 195 additions & 0 deletions src/test/java/ru/spbau/mit/LazyFactoryTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package ru.spbau.mit;

import org.junit.Test;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

import static org.junit.Assert.*;

public class LazyFactoryTest {

private static final int NUMBER_OF_THREADS = 50;

//Create suppliers

private final Supplier<String> nullSupplier = new Supplier<String>() {
private boolean isCalled = false;

@Override
public String get() {
assertFalse(isCalled);
isCalled = true;
return null;
}
};

private final Supplier<String> supplier = new Supplier<String>() {
private boolean isCalled = false;

@Override
public String get() {
assertFalse(isCalled);
isCalled = true;
return "I've done!";
}
};

//Special functions for tests

private void checkForNullTests(Lazy<String> lazy) {
assertNull(lazy.get());
assertNull(lazy.get());
}

private void checkForEqualTests(Lazy<String> lazy) {
String firstGet = lazy.get();
String secondGet = lazy.get();
assertEquals(firstGet, secondGet);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

лучше assertSame, который проверит не эквивалентность, а на ==

assertEquals(firstGet, "I've done!");
}

private Supplier<Integer> createMultiThreadSupplier(final Random random) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

не используется (IDEA подсвечивает), надо удалить

return new Supplier<Integer>() {
@Override
public Integer get() {
return random.nextInt(500);
}
};
}

private static class SupplCounter implements Supplier<Object> {
private AtomicInteger cnt = new AtomicInteger(0);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

final

private Object result;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

final


SupplCounter(Object result) {
this.result = result;
}

@Override
public Object get() {
Thread.yield();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

зачем?

cnt.incrementAndGet();
return result;
}

public Integer getCount() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

int

return cnt.get();
}
}

private void checkForMultiThread(FactoryFromSupplier factory, boolean isSupplierCalledOnce,
Object returnValue) {
SupplCounter supplier = new SupplCounter(returnValue);
Lazy<Object> lazy = factory.createLazy(supplier);

List<Thread> tasks = new ArrayList<>();
List<Object> results = Collections.synchronizedList(new ArrayList<>());
CyclicBarrier barrier = new CyclicBarrier(NUMBER_OF_THREADS);

for (int i = 0; i < NUMBER_OF_THREADS; i++) {
Thread task = new Thread(() -> {
try {
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
results.add(lazy.get());
});
tasks.add(task);
task.start();
}

for (Thread task : tasks) {
try {
task.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

С пятью потоками и простеньким run довольно трудно сделать имитацию гонки данных - лучше запустить потоки, дождаться, чтобы они дошли до определенного места с помощью барьера, а потом всем продолжить исполнение. Это будет гораздо ближе к гонке данных.


assertEquals(NUMBER_OF_THREADS, results.size());

for (Object result : results) {
assertTrue(returnValue == result);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assertSame

}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вместо этого лучше пробежаться по threads и на каждом потоке вызвать join.


assertTrue(supplier.getCount() > 0);
if (isSupplierCalledOnce) {
assertTrue(1 == supplier.getCount());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assertEquals

}
}

//Tests for one thread
@Test
public void nullTestLazyForOneThread() {
Lazy<String> lazy = LazyFactory.createLazyOneThread(nullSupplier);
checkForNullTests(lazy);
}

@Test
public void equalsTestLazyForOneThread() {
Lazy<String> lazy = LazyFactory.createLazyOneThread(supplier);
checkForEqualTests(lazy);
}

private static class classWrapper<T> {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

классы именуются с большой буквы

public volatile T content;

public classWrapper(T content) {
this.content = content;
}
}

@Test
public void lazinessTestLazyForOneThread() {
classWrapper<Boolean> isAsked = new classWrapper<>(false);

Lazy<String> lazy = LazyFactory.createLazyOneThread(() -> {
assertTrue(isAsked.content);
return "It's OK!";
});

isAsked.content = true;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ленивость проверяется только для однопоточного lazy. Лучше эту проверку засунуть в методы checkForNullTests, checkForEqualTests и checkForEqualTests


//MultiThread tests

@Test
public void nullTestLazyMultiThread() {
Lazy<String> lazy = LazyFactory.createLazyMultiThread(nullSupplier);
checkForNullTests(lazy);
}

@Test
public void equalsTestLazyMultiThread() {
Lazy<String> lazy = LazyFactory.createLazyMultiThread(supplier);
checkForEqualTests(lazy);
}

@Test
public void dataRaceTestLazyMultiThread() {
checkForMultiThread(LazyFactory::createLazyMultiThread, true, new Object());
}

//MultiThread lock-free tests

@Test
public void nullTestLazyMultiThreadLockFree() {
Lazy<String> lazy = LazyFactory.createLazyMultiThreadLockFree(nullSupplier);
checkForNullTests(lazy);
}

@Test
public void equalsTestLazyMultiThreadLockFree() {
Lazy<String> myLazy = LazyFactory.createLazyMultiThreadLockFree(supplier);
checkForEqualTests(myLazy);
}

@Test
public void dataRaceTestLazyMultiThreadLockFree() {
checkForMultiThread(LazyFactory::createLazyMultiThreadLockFree, false, new Object());
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нет теста, что вычисление только по требованию